Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rendering corruption in ASP.NET MVC 3 Razor View Engine Using Custom HTML Extension

I just installed ASP.NET MVC 3 RC to try and upgrade an MVC 2 site. I encountered a rendering problem which I managed to repro outside of the site, using an MVC 3 project created from scratch.

Here is my Razor cshtml view:

@using Mvc3RCTest.Helpers

<h2>Demo Render Bug</h2>

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

RenderTest is an HTML extension defined as follows:

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>");
        }
    }
}

When this is rendered, the HTML looks like the following:

<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>

As you can see, the output of the RenderTest HTML extension was incorrectly emitted before the rest of the Razor template. It seems as if the Razor rendering engine is trying to cache the entire output, without being aware that HTML extensions can write directly to the output.

Has anyone else seen this problem? Anyone know how to work around this, without having to redo all of my HTML extensions not to write directly to the output?

like image 651
DSO Avatar asked Dec 16 '22 20:12

DSO


1 Answers

Unfortunately, all of your helpers should be writing to the ViewContext.Writer, like so

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>");
}

Things might have worked for you in the aspx view engine, however that was purely coincidental. It's not that Razor is caching anything per se. Due to the inside-out rendering of Razor pages it writes things to temporary buffers which in turn get written to the response stream at the appropriate time only when you reach the top most layout page. If you write directly to the response stream then you will write things out of order.

like image 114
marcind Avatar answered Jan 05 '23 01:01

marcind