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

时间:2011-03-12 13:05:03

标签: .net asp.net-mvc-3 razor razor-declarative-helpers

使用MVC 3 RTM我得到一个奇怪的NullReferenceException

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

事实证明,HtmlHtmlHelper类型)是null

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

6 个答案:

答案 0 :(得分:37)

使用Drew Noakes suggestion,我现在已经找到了解决这个问题的方法,一旦在新版本的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; }
    }
}

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

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

显然,辅助方法只是一个例子。这个解决方案的缺点是必须在App_Code中的所有帮助器声明文件中引入@functions声明,但是确实避免使对helper的调用变得复杂,因为您只需在视图中写入:

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

希望这会有所帮助......

答案 1 :(得分:33)

那是known limitation of those helpers。一种可能性是将其作为参数传递:

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

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

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

然后:

@Html.TestHelperMethod()

答案 2 :(得分:23)

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

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

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

答案 3 :(得分:13)

只需替换

 @Html.Raw(extra)

@(new HtmlString(extra))

答案 4 :(得分:4)

我想我知道造成这个问题的原因......

Html属性getter的定义是:

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

在我的帮助方法中设置断点显示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

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

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

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

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

因此,如果其他人没有遇到此问题,可能他们没有使用自定义pageBaseType

另请注意,我已将@helper声明放在App_Code\Helpers.cshtml中,以期使其可全局访问。

我做错了什么,或者这是一个错误?

编辑感谢Darin指出这是一个已知问题。但是,为什么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;
    } 
} 

答案 5 :(得分:1)

我有同样的问题,这行代码就行了。这不是使用HtmlHelper的解决方案,它只是一种在声明性剃刀助手中编写RAW html的方法。

@{CurrentPage.WriteLiteral("html code");}