8

I am creating a RESTful Web Service using ASP.NET MVC 4 Web API. For API access, I am returning JSON, though once I get everything working correctly, the content negotiation should work for XML and JSON by default.

Since I am working towards a truly RESTful resource-centric web service, my URI's will be pointing to actual resources. I would like to take advantage of that by returning an HTML representation of the resource if Accepts: text/html comes in the request (like throwing the link in a browser).

I would like to be able to take advantage of MVC 4 Web API's content negotiation to insert a renderer for text/html that uses Razor templates. Are there any working examples of doing just this?

Yes, this is bridging "regular" MVC pages and Web API. Basically I'd like to create a renderer that uses a convention based approach to finding and rendering Razor views just like "regular" MVC. I can come up with the convention-based view lookup logic. I'm simply looking for a) globally inserting my text/html renderer into the content negotation, and b) using the Razor engine manually to render my model into HTML.

Kyle Trauberman
  • 25,414
  • 13
  • 85
  • 121
MikeJansen
  • 3,336
  • 3
  • 26
  • 37
  • Would redirecting to a normal controller for Html be acceptable (or executing another action via an HttpRequest and sending the results back to the client)? – Kyle Trauberman Aug 02 '12 at 18:04
  • @KyleTrauberman, I'd prefer to hook into the content negotiation. At least from my limited understanding, architecturally this would be the wisest going forward. I'm guessing the Web API and and regular MVC will come together in the future and I'd place my bets on the Web API infrastructure, so building on the content negotiation framework seems like the right way to go. Redirecting to a different controller might work but my experience leads me to believe that will be unnatural and cause trouble in the future. But I'm not opposed to understanding how that would work :) – MikeJansen Aug 02 '12 at 18:37

2 Answers2

3

Fredrik Normén has a blog post on this very topic:

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

Basically, you need to create a MediaTypeFormatter

using System;
using System.Net.Http.Formatting;

namespace WebApiRazor.Models
{
    using System.IO;
    using System.Net;
    using System.Net.Http.Headers;
    using System.Reflection;
    using System.Threading.Tasks;

    using RazorEngine;

    public class RazorFormatter : MediaTypeFormatter
    {
        public RazorFormatter()
        {
            SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html")); 
            SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/xhtml+xml"));
        }

        //...

        public override Task WriteToStreamAsync(
                                                Type type,
                                                object value,
                                                Stream stream,
                                                HttpContentHeaders contentHeaders,
                                                TransportContext transportContext)
        {
            var task = Task.Factory.StartNew(() =>
                {
                    var viewPath = // Get path to the view by the name of the type

                    var template = File.ReadAllText(viewPath);

                    Razor.Compile(template, type, type.Name);
                    var razor = Razor.Run(type.Name, value);

                    var buf = System.Text.Encoding.Default.GetBytes(razor);

                    stream.Write(buf, 0, buf.Length);

                    stream.Flush();
                });

            return task;
        }
    }
}

and then register it in Global.asax:

GlobalConfiguration.Configuration.Formatters.Add(new RazorFormatter());

the above code is copied from the blog post and is not my work

Kyle Trauberman
  • 25,414
  • 13
  • 85
  • 121
0

You might take a look at WebApiContrib.Formatting.Razor. It's very similar to Kyle's answer, however it's a full-blown open source project with more features, unit tests, etc. You can get it on NuGet as well.

I will say it definitely needs more features, but they seem to have designed it well so it would be very easy to contribute to it.

Phil
  • 6,561
  • 4
  • 44
  • 69