Render Razor view to string in ASP.NET 5

In previous versions of ASP.NET it was possible, although not very simple, to render Razor views as strings. The methods I've seem are to use a fake controller, or also to use some external engine like RazorEngine.

Now, many things are changed with ASP.NET 5 and I was wondering whether or not this is now simpler than before. So in the new version of the framework is there one straightforward way to render Razor views as strings or we still need to use the methods from the previous versions?


Solution 1:

I use the following types injected from the IServiceProvider:

ICompositeViewEngine viewEngine;
ITempDataProvider tempDataProvider;
IHttpContextAccessor httpContextAccessor;

I render the content using the following method:

private async Task<string> RenderView(string path, ViewDataDictionary viewDataDictionary, ActionContext actionContext)
{
    using (var sw = new System.IO.StringWriter())
    {
        var viewResult = viewEngine.FindView(actionContext, path);

        var viewContext = new ViewContext(actionContext, viewResult.View, viewDataDictionary, new TempDataDictionary(httpContextAccessor, tempDataProvider), sw);

        await viewResult.View.RenderAsync(viewContext);
        sw.Flush();

        if (viewContext.ViewData != viewDataDictionary)
        {
            var keys = viewContext.ViewData.Keys.ToArray();
            foreach (var key in keys)
            {
                viewDataDictionary[key] = viewContext.ViewData[key];
            }
        }

        return sw.ToString();
    }
}

I call it like this:

var path = "~/Views/Home/Index.cshtml";
var viewDataDictionary = new ViewDataDictionary(new Microsoft.AspNet.Mvc.ModelBinding.EmptyModelMetadataProvider(), new Microsoft.AspNet.Mvc.ModelBinding.ModelStateDictionary());
var actionContext = new ActionContext(httpContextAccessor.HttpContext, new Microsoft.AspNet.Routing.RouteData(), new ActionDescriptor());
viewDataDictionary.Model = null;
var text = await RenderView(path, viewDataDictionary, actionContext);

Of course, my viewDataDictionary and actionContext variables are set by another method for encapsulation. A modification to the new ViewDataDictionary line can result in a typed Model being bound to your View if you choose.

This code uses heavy usings, I think I've listed them below. Otherwise, VS2015 is pretty good about finding them.

using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Rendering;

This was written under beta-3; it still builds, but some things may change. I'll try to come back here to update if it does.

Solution 2:

There is a solution that I've used an year ago. I'm not sure if there is a new/better way to do, but it solves the problem.

public string RenderViewToString(string viewName, object model)
{
    ViewData.Model = model;
    using (var sw = new StringWriter())
    {
       var viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
       var viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
       viewResult.View.Render(viewContext, sw);
       viewResult.ViewEngine.ReleaseView(ControllerContext, viewResult.View);
       return sw.GetStringBuilder().ToString();
     }
}