代码之家  ›  专栏  ›  技术社区  ›  dso

使用自定义HTML扩展在ASP.NET MVC 3 Razor视图引擎中呈现损坏

  •  4
  • dso  · 技术社区  · 14 年前

    我刚刚安装了ASP.netmvc3rc来尝试升级MVC 2站点。我遇到了一个渲染问题,我用一个从头开始创建的MVC 3项目在站点外重新编程。

    这是我的Razor 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>
    

    如您所见,RenderTest HTML扩展的输出被错误地发出 之前 剃刀模板的其余部分。似乎Razor渲染引擎正在尝试缓存整个输出,而没有意识到HTML扩展可以直接写入输出。

    还有人看到这个问题吗?有谁知道如何解决这个问题,而不必重做所有的HTML扩展,不直接写入输出?

    2 回复  |  直到 14 年前
        1
  •  9
  •   marcind    14 年前

    不幸的是,你所有的助手都应该写信给 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视图引擎中,事情可能对您有用,但这纯属巧合。不是Razor本身在缓存任何东西。由于Razor页面是由内向外呈现的,所以它会将内容写入临时缓冲区,而临时缓冲区又会在适当的时间写入响应流,只有当您到达最上面的布局页面时。如果您直接写入响应流,那么您将按顺序写入内容。

        2
  •  3
  •   Darin Dimitrov    14 年前

    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中的程序集,因此请确保引用了它。