为什么在Razor声明式@helper方法中HtmlHelper实例为null?

Dre*_*kes 36 .net razor razor-declarative-helpers asp.net-mvc-3

使用MVC 3 RTM我变得很奇怪NullReferenceException:

@helper TestHelperMethod() {
    var extra = "class=\"foo\"";
    <div @Html.Raw(extra)></div>
}
Run Code Online (Sandbox Code Playgroud)

事实证明Html(类型HtmlHelper)是null.

我以前从未在常规视图中看过这个.我开始在Razor中尝试声明性辅助方法(到目前为止它们似乎有点受限)并且我对我在这里看到的东西感到非常难过.

kka*_*ara 38

使用Drew Noakes的建议,我已经找到了一个现在可以解决这个问题的解决方法,一旦在更新版本的MVC中解决问题就可以轻松删除(即如果更多的东西没有改变会破坏它:) )

目标是能够在声明性帮助器方法中使用HtmlHelper,该方法位于App_Code中的文件中,而不会出现NullReferenceException.为了解决这个问题,我在App_Code中包含了以下所有文件:

@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; }
    }
}
Run Code Online (Sandbox Code Playgroud)

这似乎可以解决问题,因为我现在可以编写以下帮助程序(在同一个文件中):

@helper PrintAsRaw(string htmlString)
{
     @Html.Raw(htmlString)
}
Run Code Online (Sandbox Code Playgroud)

显然,辅助方法只是一个例子.这个解决方案的缺点是必须在App_Code中的所有帮助器声明文件中引入@functions声明,但是确实避免了对辅助器的调用复杂化,因为您可以简单地在视图中写入:

@MyAppCodeFile.PrintAsRaw("<p>My paragraph</p>")
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助...


Dar*_*rov 33

是那些助手已知限制.一种可能性是将其作为参数传递:

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

另一种可能性是将助手编写为扩展方法:

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

然后:

@Html.TestHelperMethod()
Run Code Online (Sandbox Code Playgroud)

  • @PraveenPrasad,我看到没有人回答你的问题.这有点晚了,但是,要调用他的第一个解决方案(声明性帮助器),您将从调用代码传递"System.Web.Mvc.HtmlHelper"对象的本地实例:TestHelperMethod(Html).确保完全限定名称空间,因为"HtmlHelper"存在于2个名称空间中,如上所述,并且似乎默认为错误的名称(至少在我的代码中这样做). (2认同)

Bri*_*per 23

我知道这不是重点,但是Html.Raw(value)根据System.Web.Mvc.dll的源代码,如果只是你希望在谷歌上找到这个问题时使用(就像我一样)所有的Html.Raw都是:

public IHtmlString Raw(string calue)
{
    return new HtmlString(value);
}
Run Code Online (Sandbox Code Playgroud)

所以我刚刚@(new HtmlString(value))在我的助手中使用过,效果很好.

  • 这绝对是最简单的解决方案. (2认同)
  • 太好了!我已经用它来编写我的助手以在我的助手中使用:) - `@helper Raw(字符串值){@(new HtmlString(value))}` (2认同)

Ott*_*lis 14

只需更换

 @Html.Raw(extra)
Run Code Online (Sandbox Code Playgroud)

@(new HtmlString(extra))
Run Code Online (Sandbox Code Playgroud)


Dre*_*kes 5

我想我知道导致问题的原因...

Html属性获取器的定义是:

public static HtmlHelper Html {
    get { 
        WebPage currentWebPage = CurrentPage as WebPage;
        if (currentWebPage == null) {
            return null;
        } 
        return currentWebPage.Html;
    } 
} 
Run Code Online (Sandbox Code Playgroud)

在我的辅助方法中设置一个断点表明CurrentPage实际上不是的实例WebPage,因此不是该null值。

这是CurrentPage(我的班级名称略有修改)的类型层次结构:

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
Run Code Online (Sandbox Code Playgroud)

请注意,我的视图的基类已在Web.config中指定:

<system.web.webPages.razor>
  <pages pageBaseType="My.Site.MyWebViewPage">
    ...
Run Code Online (Sandbox Code Playgroud)

它以通用和非通用形式定义:

public abstract class MyWebViewPage : WebViewPage { ... }
public abstract class MyWebViewPage<TModel> : WebViewPage<TModel> { ... }
Run Code Online (Sandbox Code Playgroud)

因此,如果其他人没有发生此问题,则可能他们没有使用custom pageBaseType

还要注意,我已将该@helper声明放置App_Code\Helpers.cshtml在希望使其可全局访问的位置。

我是在做错什么,还是一个错误?

编辑感谢达林指出这是一个已知问题。不过,为什么不将Html属性重新定义为:

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;
    } 
} 
Run Code Online (Sandbox Code Playgroud)

  • 我们当然意识到,目前关于帮助者的故事还不够,我们计划在下一个版本中加以解决。 (2认同)