nik codes

Flushing in ASP.NET MVC

I’ve written a follow up to this post that answers many of the common questions about flushing early. Be sure to check it out.

The Setting

Before the beginning of this decade, Steve Souders released two seminal books on the topic of web performance: High Performance Web Sites and Even Faster Web Sites. The findings and subsequent suggestions that came out of those books changed the face of web development and have been codified into several performance analysis tools including Yahoo YSlow and Google PageSpeed.

High Performance Web Sites Even Faster Web Sites

Most professional web developers that I’ve met over the past five years are familiar with Souder’s recommendations and how to implement them in ASP.NET MVC. To be fair, they aren’t that difficult:

  • HTTP Caching and Content Compression can both be enabled simply via a few settings in web.config.
  • Layout pages make it easy to put stylesheets at the top of a page and scripts at the bottom in a consistent manner.
  • The Microsoft.AspNet.Web.Optimization NuGet package simplifies the ability to combine and minify assets.
  • And so on, and so forth…

The recommendation to “Flush the Buffer Early” (covered in depth in chapter 12 of Even Faster Web Sites), however, is not so easy to implement in ASP.NET MVC. Here’s an explanation of the recommendation from Steve’s 2009 blog post:

Flushing is when the server sends the initial part of the HTML document to the client before the entire response is ready. All major browsers start parsing the partial response. When done correctly, flushing results in a page that loads and feels faster. The key is choosing the right point at which to flush the partial HTML document response. The flush should occur before the expensive parts of the back end work, such as database queries and web service calls. But the flush should occur after the initial response has enough content to keep the browser busy. The part of the HTML document that is flushed should contain some resources as well as some visible content. If resources (e.g., stylesheets, external scripts, and images) are included, the browser gets an early start on its download work. If some visible content is included, the user receives feedback sooner that the page is loading.

A few months ago Steve revisited this guidance and provided examples of the difference that flushing can make to an application’s performance. His post inspired me to try the same on an ASP.NET MVC project that I’m working on, which led to this post.

The Conflict

Since .NET 1.1, ASP.NET has provided a mechanism to flush a response stream to the client with a simple call to HttpResponse.Flush(). This works quite well when you are incrementally building up a response, but the architecture of MVC, with its use of the command pattern, doesn’t really allow for this. (At least not in a clean manner.) Adding a call to Flush() inside a view doesn’t do much good.

@{
     Response.Flush();
}

This is because MVC doesn’t execute the code in the view until all the other work in the controller has completed – essentially the opposite of what the czar of web performance recommends.

The Climax

Because I’m a believer that #PerfMatters, I decided to take matters into my own hands to see if I could do anything better.

First, I realized that I could can get around a few issues by leveraging partial results, manually executing and flushing them, like so:

public ActionResult FlushDemo()
{
       PartialView("Head").ExecuteResult(ControllerContext);
       Response.Flush();

       // do other work
       return PartialView("RemainderOfPage");
}

I think that looks pretty ugly, so I’ve taken things a step farther and removed the cruft around executing the result by creating a base controller with its own Flush() method:

public class BaseController : Controller
{
     public void Flush(ActionResult result)
     {
         result.ExecuteResult(ControllerContext);
         Response.Flush();
     }
}

I think my new Flush() method clarifies the intent in the action method:

public ActionResult FlushDemo()
{
     Flush(PartialView("Head"));

     // do other work
     return PartialView("RemainderOfPage");
}

What I’d really like to be able to do is leverage the yield keyword. Yield seems like the natural language and syntax to express this. I was able to cobble together this example:

public IEnumerable<ActionResult> Test()
{
      yield return PartialView("Header");
      Thread.Sleep(2000); // or other work

      yield return PartialView("Lorem");
      Thread.Sleep(2000); // or other work

      yield return PartialView("Vestibulum");
      Thread.Sleep(2000); // or other work

      yield return PartialView("Sed");
      Thread.Sleep(2000); // or other work

      yield return PartialView("Footer");
}

I got that working with a pretty ugly hack, but leveraging the yield keyword and IEnumerable<ActionResult> like this should theoretically be possible by making a few changes to MVC’s default action invoker, no hack necessary.  Unfortunately, C# throws a few curve balls at this since you can’t combine the usage of yield with async/await – which I think would be a pretty common usage scenario.

The Resolution?

It looks like splitting up a layout file into multiple partial views and using my Flush() helper method is the best that we can do right now.

Unfortunately,

  • Yielding multiple views isn’t currently supported by MVC, and even if it was it would be incompatible with the current C# compiler.
  • Partial views are the best we can get to break up a response into multiple segments – which is painful. It’d be nice if I could ask Razor to render just a section of a layout page, which would reduce the need for partial views.

I’m hoping that the ASP.NET team, or my readers, can come up with a better way to handle flushing in the future, but I wanted to at least walk you through what your options are today.

For those interested, I might pull together some of this thinking into a NuGet package that leverages action filter attributes to simplify the syntax even further. If you like the sounds of that, encourage me on Twitter: @nikmd23

About these ads

Single Post Navigation

17 thoughts on “Flushing in ASP.NET MVC

  1. Pingback: Dew Drop – March 5, 2014 (#1736) | Morning Dew

  2. jamolina on said:

    Great idea, you should really post it in the VS User Voice page: http://visualstudio.uservoice.com/forums/121579-visual-studio

  3. nikmd23 on said:

    Thanks jamolina! I just might do that.

  4. Pingback: Flushing in ASP.NET MVC | StupidPC.com

  5. Jacob on said:

    How would that work when compressing the http output?

    • nikmd23 on said:

      Jacob, IIS seems to handle this fine – meaning the content (each flushed part) is still encrypted. I could not create dynamic content small enough that IIS would skip compression.

      I’m working on a follow up post to answer common questions that came up from this post. I’ll provide more details for you there.

  6. Do you have a sample project ?

  7. nikmd23 on said:

    ignatandrei, you’re not the only one who has asked for this, so I am working on a follow up blog post and sample. Watch this space for that soon.

  8. DkUltra on said:

    What about using editor templates and flushing after each one is done/ at the bottom of one .

    • nikmd23 on said:

      Editor templates don’t execute through the MVC view engine infrastructure. This means that they aren’t written to the response stream directly, but rather as part of a view.

  9. Pingback: More HTTP Flushing in ASP.NET MVC | nik codes

  10. nikmd23 on said:

    My promised follow up post has been published: http://nikcodes.com/2014/03/17/more-http-flushing-in-asp-net-mvc/

  11. Rahul Sarkar on said:

    Hi Nik,
    Nice stuff. Omar has implemented it in another way which let’s one retain layout. See if this http://www.codeproject.com/Articles/755672/Faster-page-rendering-by-downloading-JS-CSS-before
    helps ?

    • nikmd23 on said:

      Thanks for sending this link through! I’m not a fan of his implementation, but it is an interesting to see how he thinks of the problem, and that he’s trying to fix it as well.

  12. Pingback: PerfMatters.Flush Goes 1.0! | nik codes

  13. Hi Nik,
    Nice stuff. I’m wondering if it works well with MVC OutputCache attribute. Will my website be benefit if it has already had the OutputCache attribute decorated?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: