Why is the HtmlHelper instance null in a Razor declarative @helper method?

前端 未结 6 1507
余生分开走
余生分开走 2020-12-15 15:22

Using MVC 3 RTM I\'m getting a strange NullReferenceException:

@helper TestHelperMethod() {
    var extra = \"class=\\\"foo\\\"\";
    
相关标签:
6条回答
  • 2020-12-15 15:56

    That's a known limitation of those helpers. One possibility is to pass it as parameter:

    @helper TestHelperMethod(HtmlHelper html) {
        var extra = "class=\"foo\"";
        <div@html.Raw(extra)></div>
    }
    

    Another possibility is to write the helper as an extension method:

    public static class HtmlExtensions
    {
        public static MvcHtmlString TestHelperMethod(this HtmlHelper)
        {
            var div = new TagBuilder("div");
            div.AddCssClass("foo");
            return MvcHtmlString.Create(div.ToString());
        }
    }
    

    and then:

    @Html.TestHelperMethod()
    
    0 讨论(0)
  • 2020-12-15 16:05

    I had the same issue and this line of code did the trick. It´s not a solution for using HtmlHelper, it's just a way of writing RAW html in a declarative razor helper.

    @{CurrentPage.WriteLiteral("html code");}
    
    0 讨论(0)
  • 2020-12-15 16:09

    Using Drew Noakes suggestion, I have come to a workaround that does the trick for now and that can be easily removed once the issue is solved in a newer version of MVC (that is if more stuff isn't changed that would break it:))

    The goal is to be able to use an HtmlHelper inside a declarative helper method that lives in a file in App_Code without having a NullReferenceException. To solve this I included in all the files in App_Code the following:

    @using System.Web.Mvc;
    
    @functions
    {
        private static new HtmlHelper<object> Html
        {
            get { return ((WebViewPage)CurrentPage).Html; }
        }
    
        private static UrlHelper Url
        {
            get { return ((WebViewPage)CurrentPage).Url; }
        }
    }
    

    This does seem to do the trick as I can now write the following helper (in the same file):

    @helper PrintAsRaw(string htmlString)
    {
         @Html.Raw(htmlString)
    }
    

    Obviously the helper method is just an example. This solution has the downside that the @functions declarations has to be introduced in all helper declaration files in App_Code, but does avoid complicating the call to the helper, as you can simply write in a view:

    @MyAppCodeFile.PrintAsRaw("<p>My paragraph</p>")
    

    Hope this helps...

    0 讨论(0)
  • 2020-12-15 16:11

    I know it's not the point but if it is just Html.Raw(value) you were hoping to use when finding this question on Google (as I was) according to the source code of System.Web.Mvc.dll all Html.Raw does is:

    public IHtmlString Raw(string calue)
    {
        return new HtmlString(value);
    }
    

    So I've just used @(new HtmlString(value)) in my helper which works nicely.

    0 讨论(0)
  • 2020-12-15 16:12

    Just replace

     @Html.Raw(extra)
    

    with

    @(new HtmlString(extra))
    
    0 讨论(0)
  • 2020-12-15 16:16

    I think I know what's causing the issue...

    The definition of the Html property getter is:

    public static HtmlHelper Html {
        get { 
            WebPage currentWebPage = CurrentPage as WebPage;
            if (currentWebPage == null) {
                return null;
            } 
            return currentWebPage.Html;
        } 
    } 
    

    Setting a breakpoint in my helper method shows that CurrentPage is not in fact an instance of WebPage, hence the null value.

    Here is the type hierarchy of CurrentPage (my class names doctored slightly):

    ASP._Page_Views_mycontroller_View_cshtml
      My.Site.MyWebViewPage`1
        System.Web.Mvc.WebViewPage`1
          System.Web.Mvc.WebViewPage
            System.Web.WebPages.WebPageBase
              System.Web.WebPages.WebPageRenderingBase
                System.Web.WebPages.WebPageExecutingBase
                  System.Object
    

    Note that the base class of my view has been specified in Web.config:

    <system.web.webPages.razor>
      <pages pageBaseType="My.Site.MyWebViewPage">
        ...
    

    Which is defined both in generic and non-generic form:

    public abstract class MyWebViewPage : WebViewPage { ... }
    public abstract class MyWebViewPage<TModel> : WebViewPage<TModel> { ... }
    

    So, if this problem does not occur for others, perhaps they're not using a custom pageBaseType.

    Note too that I've placed the @helper declaration in App_Code\Helpers.cshtml in the hope of making it globally accessible.

    Am I doing something wrong, or is this a bug?

    EDIT Thanks Darin for pointing out this as a known issue. Still, why isn't the Html property redefined as:

    public static HtmlHelper Html {
        get { 
            WebPage currentWebPage = CurrentPage as WebPage;
            if (currentWebPage != null) {
                return currentWebPage.Html;
            } 
            WebViewPage currentWebViewPage = CurrentPage as WebViewPage;
            if (currentWebViewPage != null) {
                return currentWebViewPage.Html;
            } 
            return null;
        } 
    } 
    
    0 讨论(0)
提交回复
热议问题