Friday, October 12, 2012

Rendering an ASP.NET MVC View to a string in a Web Api Controller

Today I was working on a Web Api Controller that integrated with a third party application. The application wants us to return an XML document. One of the nodes is a piece of HTML that is displayed in the application.

So I started thinking about a flexible way to render HTML from a WebApi Controller. After searching around on the web I came up with a solution.

Sneaking my way into MVC


The biggest problem was that rendering a View is something that normally shouldn't happen inside Web Api (see this discussion why not). The solutions I found on the web all use some kind of MediaTypeFormatter to return HTML when the client requests it. 

However, that's not what I want. I want to return the following data to the client where the Body property should contain an HTML string:

public class ContentItem
{
    public string Title { get; set; }
    public string Body { get; set; }
    public string Widgets { get; set; }
}

Eventually this is what I came up with:

public static string RenderViewToString(string controllerName, string viewName, 
                                         object viewData)
{
    HttpContextBase contextBase = this.HttpContext.Current;

    var routeData = new RouteData();
    routeData.Values.Add("controller", controllerName);
    var controllerContext = new ControllerContext(contextBase, routeData, 
                                                   new EmptyController());

    var razorViewEngine = new RazorViewEngine();
    var razorViewResult = razorViewEngine.FindView(controllerContext, viewName, 
                                                     "", false);

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

    return writer.ToString();
}

private class EmptyController : ControllerBase
{
    protected override void ExecuteCore() { }
}

You can simply call this from anywhere in your Web Api Controller: 

RenderViewToString("controller", "view", model)
Do you have run into similar issues? Can you use this code or do you have another idea? Please leave a comment!

4 comments:

  1. thanks

    HttpContextBase contextBase = new HttpContextWrapper(HttpContext.Current);

    this line must change with

    HttpContextBase contextBase = this.HttpContext;

    ReplyDelete
    Replies
    1. Thanks for your help! I've updated the code

      Delete
  2. I mainly need to return html page to the user from the webApi controller action. You mentioned that you found a solution using MediaTypeFormatter?

    ReplyDelete
    Replies
    1. Hi George,

      thanks for your reply! I hope this link can help you:

      http://weblogs.asp.net/fredriknormen/archive/2012/06/28/using-razor-together-with-asp-net-web-api.aspx

      If not, let me know!

      Wouter

      Delete