Почему экземпляр HtmlHelper имеет нулевое значение в декларативном методе Razor @helper? - PullRequest
35 голосов
/ 12 марта 2011

При использовании MVC 3 RTM я получаю странное NullReferenceException:

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

Оказывается, Html (типа HtmlHelper) равно null.

Я никогда не видел этого раньше в обычном представлении. Я начинаю экспериментировать с декларативными вспомогательными методами в Razor (пока они кажутся немного ограниченными), и я весьма озадачен тем, что вижу здесь.

Ответы [ 6 ]

37 голосов
/ 11 августа 2011

Используя предложение Дрю Ноакса , я пришел к обходному пути, который пока работает, и его можно легко устранить, как только проблема будет решена в более новой версии 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)
}

Очевидно, что вспомогательный метод является лишь примером.Недостатком этого решения является то, что объявления @functions необходимо вводить во все файлы объявлений помощника в App_Code, но избегает усложнения вызова помощника, так как вы можете просто написать в представлении:

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

Надеюсь, это поможет ...

33 голосов
/ 12 марта 2011

Это известное ограничение этих помощников . Одна возможность - передать его в качестве параметра:

@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()
23 голосов
/ 30 апреля 2012

Я знаю, что это не главное, но если это просто Html.Raw(value), который вы надеялись использовать при поиске этого вопроса в Google (как я) в соответствии с исходным кодом System.Web.Mvc.dll all Html.Raw делает это:

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

Так что я просто использовал @(new HtmlString(value)) в своем помощнике, который прекрасно работает.

14 голосов
/ 24 апреля 2013

Просто замените

 @Html.Raw(extra)

с

@(new HtmlString(extra))
4 голосов
/ 12 марта 2011

Мне кажется, я знаю, что является причиной проблемы ...

Определение метода получения свойства Html:

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 в надежде сделать это глобальнодоступный.

Я что-то не так делаю, или это ошибка?

EDIT Спасибо, Дарин, за то, что указал на это как на известную проблему.Тем не менее, почему свойство 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;
    } 
} 
1 голос
/ 06 марта 2012

У меня была та же проблема, и эта строка кода добилась цели.Это не решение для использования HtmlHelper, это просто способ написания RAW html в декларативном помощнике бритвы.

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