How to render a view to a string in ASP.NET MVC

03 December 2014

It's a pretty common requirement if you need a view or partial rendered as a string.

For example: In a product database you have different articles for each product, which define the different colors. Each article contains an availability table for each size.

If you want to live update the site when changing the color (therefore article), you can make an AJAX request or pre-include the JSON with the necessary article data. Each article will contain some data like sizes, images, price, ... and also the pre-rendered availability table (which will replace the old one).

Creating this JSON is easy. The tricky part is pre-rendering HTML which should be included as part of the JSON (or other format) response.

Requirement

You will need access to the System.Web.Mvc namespace and a reference to the current ControllerContext, which is defined in System.Web.Mvc.ControllerBase and available in every controller.

How-To

Create an utility class which contains your new method to render views to a string:

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

namespace App.Utilities
{
  public static class ViewUtilities
  {
    public static string Render(string viewName, object model, ControllerContext controllerContext, ViewDataDictionary viewData = null, TempDataDictionary tempData = null)
    {

    }
  }
}

All necessary classes are contained in the System.Web.Mvc namespace, so don't forget to require it. The System.IO namespace is required for the StringWriter we are using later on.

public static string RenderViewToString(string viewName, object model, ControllerContext controllerContext, ViewDataDictionary viewData = null, TempDataDictionary tempData = null)
{
  if (viewData == null)
  {
    viewData = new ViewDataDictionary();
  }
  if (tempData == null)
  {
    tempData = new TempDataDictionary();
  }

  // assing model to the viewdata
  viewData.Model = model;

  using (var sw = new StringWriter())
  {
    // try to find the specified view
    ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(controllerContext, viewName);
    // create the associated context
    ViewContext viewContext = new ViewContext(controllerContext, viewResult.View, viewData, tempData, sw);
    // write the render view with the given context to the stringwriter
    viewResult.View.Render(viewContext, sw);

    viewResult.ViewEngine.ReleaseView(controllerContext, viewResult.View);
    return sw.GetStringBuilder().ToString();
  }
}

Don't worry, it's pretty simple to understand.

  1. First we check for the existence of the ViewDataDictionary and the TempDataDictionary. The ViewData is used so you can access your data in the view. And the associated model, in case you have one.

    These dictionaries are required by the ViewContext.

  2. Next we create the StringWriter where we can render the view to.

  3. ViewEngines.Engines.FindPartialView(controllerContext, viewName);
    The selected ViewEngine tries to locate our view here. In case it can't find it, it will throw an exception with a list of all the places where it took a look.

  4. new ViewContext(controllerContext, viewResult.View, viewData, tempData, sw);
    The ViewContext contains data from the Controller, your ViewData with the model and the TempData. This is a pretty important line, as it creates the context for the view and therefore the data which you will access in your view.

  5. viewResult.View.Render(viewContext, sw);
    In this line the view gets rendered and written to the StringWriter, so we can create the string from it later on.

  6. viewResult.ViewEngine.ReleaseView(controllerContext, viewResult.View);
    ReleaseView releases the view so it can be used again and we can finally create our string with sw.GetStringBuilder().ToString() and return it.

Example

An example model:

public class Availability
{
    public string Size { get; set; }
    public int Stock { get; set; }
}

Partial View (in /Views/_Availability.cshtml):

@model App.Models.Availability

The article with size @Model.Size has @Model.Stock units available.

In our controller we can create a new action with a JSON result, and return the article with the attached availability information rendered as HTML:

public JsonResult GetArticle()
{
  return Json(new {
    Id = 12832,
    Name = "Shoe v2",
    Availability = ViewUtilities.RenderViewToString("_Availability", new Availability() { Size = "XL", Stock = 92 }, ControllerContext)
  });
}

Happy coding

comments powered by Disqus