MVC 5 Render View to String

following is the solution that works with session and areas on MVC5.

public class FakeController : ControllerBase
{
    protected override void ExecuteCore() { }
    public static string RenderViewToString(string controllerName, string viewName,string areaName, object viewData,RequestContext rctx)
    {
        try
        {
            using (var writer = new StringWriter())
            {
                var routeData = new RouteData();
                routeData.Values.Add("controller", controllerName);
                routeData.Values.Add("Area", areaName);
                routeData.DataTokens["area"] = areaName;

                var fakeControllerContext = new ControllerContext(rctx, new FakeController());
                //new ControllerContext(new HttpContextWrapper(new HttpContext(new HttpRequest(null, "http://google.com", null), new HttpResponse(null))), routeData, new FakeController());
                fakeControllerContext.RouteData = routeData;

                var razorViewEngine = new RazorViewEngine();

                var razorViewResult = razorViewEngine.FindView(fakeControllerContext, viewName, "", false);

                var viewContext = new ViewContext(fakeControllerContext, razorViewResult.View, new ViewDataDictionary(viewData), new TempDataDictionary(), writer);

                razorViewResult.View.Render(viewContext, writer);
                return writer.GetStringBuilder().ToString();
                //use example
                //String renderedHTML = RenderViewToString("Email", "MyHTMLView", myModel );
                //where file MyHTMLView.cstml is stored in Views/Email/MyHTMLView.cshtml. Email is a fake controller name.
            }
        }
        catch (Exception ex)
        {
            //do your exception handling here
        }
    }
}

here is how you call this from another controller

var modal = getModal(params);
return FakeController.RenderViewToString(controllerName, viewName, areaName, modal, this.Request.RequestContext);

using requestcontext we can easily pass current session in fakecontroller and render razor string.


Ok, seems I found a solution. Author of the idea is Yakir Manor.

class FakeController : ControllerBase
{
    protected override void ExecuteCore() { }
    public static string RenderViewToString(string controllerName, string viewName, object viewData)
    {
        using (var writer = new StringWriter())
        {
            var routeData = new RouteData();
            routeData.Values.Add("controller", controllerName);
            var fakeControllerContext = new ControllerContext(new HttpContextWrapper(new HttpContext(new HttpRequest(null, "http://google.com", null), new HttpResponse(null))), routeData, new FakeController());
            var razorViewEngine = new RazorViewEngine();
            var razorViewResult = razorViewEngine.FindView(fakeControllerContext, viewName, "", false);

            var viewContext = new ViewContext(fakeControllerContext, razorViewResult.View, new ViewDataDictionary(viewData), new TempDataDictionary(), writer);
            razorViewResult.View.Render(viewContext, writer);
            return writer.ToString();

        }
    }
}

It's a trick with fake context and response.

Example:

String renderedHTML = RenderViewToString("Email", "MyHTMLView", myModel );

My file MyHTMLView.cshtml is stored in Views/Email/MyHTMLView.cshtml. Email is a fake controller name.