Рендеринг коррупции в ASP.NET MVC 3 Razor View Engine с использованием пользовательского расширения HTML - PullRequest
4 голосов
/ 14 ноября 2010

Я только что установил ASP.NET MVC 3 RC, чтобы попытаться обновить сайт MVC 2. Я столкнулся с проблемой рендеринга, которую мне удалось воспроизвести за пределами сайта, используя проект MVC 3, созданный с нуля.

Вот мой вид бритвы cshtml:

@using Mvc3RCTest.Helpers

<h2>Demo Render Bug</h2>

<div class="content">
@{ Html.RenderTest(); }
</div>

RenderTest - это расширение HTML, определенное следующим образом:

using System.Web;
using System.Web.Mvc;

namespace Mvc3RCTest.Helpers
{
    public static class TestHtmlExtensions
    {
        public static void RenderTest(this HtmlHelper html)
        {
            HttpResponseBase r = html.ViewContext.HttpContext.Response;
            r.Write("<ul>");
            for (int i = 0; i < 10; ++i)
            {
                r.Write("<li>" + i + "</li>");
            }
            r.Write("</ul>");
        }
    }
}

Когда это отображается, HTML выглядит следующим образом:

<ul><li>0</li><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li></ul>
<h2>Demo Render Bug</h2>

<div class="content">
</div>

Как видите, выходные данные расширения HTML RenderTest были неправильно отправлены до остальной части шаблона Razor. Кажется, что движок рендеринга Razor пытается кэшировать весь вывод, не зная, что расширения HTML могут писать напрямую в вывод.

Кто-нибудь еще видел эту проблему? Кто-нибудь знает, как обойти это, без необходимости переделывать все мои HTML-расширения, чтобы не записывать напрямую в вывод?

Ответы [ 2 ]

9 голосов
/ 14 ноября 2010

К сожалению, все ваши помощники должны писать в ViewContext.Writer, вот так

public static void RenderTest(this HtmlHelper html)
{
    var writer = html.ViewContext.Writer;
    writer.Write("<ul>");
    for (int i = 0; i < 10; ++i)
    {
        writer.Write("<li>" + i + "</li>");
    }
    writer.Write("</ul>");
}

В движке aspx view у вас могло бы получиться, однако это было чисто случайным.Дело не в том, что Razor что-то кеширует как таковой.Из-за визуализации страниц Razor наизнанку он записывает данные во временные буферы, которые, в свою очередь, записываются в поток ответов в соответствующее время, только когда вы достигаете самой верхней страницы макета.Если вы пишете прямо в поток ответов, вы будете писать вещи не по порядку.

3 голосов
/ 14 ноября 2010

Html-помощники обычно возвращают MvcHtmlString вместо прямой записи в ответ.Запись непосредственно в ответ напоминает мне о старых классических элементах управления WebForms :-)

public static MvcHtmlString RenderTest(this HtmlHelper html)
{
    var ul = new TagBuilder("ul");
    var sb = new StringBuilder();
    for (int i = 0; i < 10; ++i)
    {
        var li = new TagBuilder("li");
        li.SetInnerText(i.ToString());
        sb.Append(li.ToString());
    }
    ul.InnerHtml = sb.ToString();
    return MvcHtmlString.Create(ul.ToString());
}

В качестве дополнительного примечания класс TagBuilder был перемещен в сборку System.Web.WebPages в MVC 3 RC, поэтому убедитесьна это ссылаются.

...