Combine WCF MediaTypeProcessors with a Custom Razor Host

There is a bunch of cool stuff coming out of Microsoft right now. As I’ve previously blogged, WCF Web APIs is one of them. One of the cool things that was shown by Glenn Block at PDC a couple of weeks ago was Media Type Processors. Media Type Processors provide a way to allow the consumer of your service to be able to specify the format they want on their response simply by setting the Accept header on the request (and thereby allowing your service to conform to HTTP standards). Out of the box, WCF will support xml, json, and OData. However, at PDC, they also demonstrated building a PngProcessor which would return a png image from WCF by setting the Accept header to “image/png”. Yes, you heard that right – WCF returning an image!

In the PDC demo, a Contact Manager application was used to show that you could request the same URI for a given contact but get back different representations for that resource depending on the requested media type. The WCF code for the service knows nothing of formats – it is only concerned the logic for returning the appropriate resource. The concerns for the formatting is totally encapsulated in the media type processors. For example, (using Fiddler) and executing a GET request for “/contact/4”, a default request returns XML:



An Accept header of “application/json” results in json:



An Accept header of “image/png” results in an image (made possible by the PngProcessor):



All for the same URI.

Wouldn’t it also be nice to be able to return HTML if a consumer specified an Accept header of “text/html”? Wouldn’t it be nice to just hook this into the WCF pipeline? And wouldn’t it also be nice to be able to use the Razor view engine even though we’re using WCF and not MVC 3?  Andrew Nurse recently had a blog post which gave details on how to host Razor outside of ASP.NET. This was also demonstrated at PDC. (If you don’t think that is cool, you might have to check to make sure you still have a pulse)

I want to be able to use a Razor template that looks something like this:

   1:  <html>
   2:      <body>
   3:          <p>Name: @Model.Name</p>
   4:          <p>Email: @Model.Email</p>
   5:          <p>Address: @Model.Address</p>
   6:          <p>City: @Model.City</p>
   7:          <p>State: @Model.State</p>
   8:          <p>Zip: @Model.Zip</p>
   9:          <p>Twitter: @Model.Twitter</p>
  10:      </body>
  11:  </html>

Now I need some way to invoke that Razor template. But I also need to be able to specify a model. In order to do that, I’ll make a slight change to the TemplateBase class that Andrew Nurse provided in his sample:

   1:  public abstract class TemplateBase
   2:  {
   3:      public StringBuilder Buffer { get; set; }
   4:      public StringWriter Writer { get; set; }
   6:      public TemplateBase()
   7:      {
   8:          Buffer = new StringBuilder();
   9:          Writer = new StringWriter(Buffer);
  10:      }
  12:      public abstract void Execute();
  14:      public virtual void Write(object value)
  15:      {
  16:          WriteLiteral(value);
  17:      }
  19:      public virtual void WriteLiteral(object value)
  20:      {
  21:          Buffer.Append(value);
  22:      }
  24:      public dynamic Model { get; set; }
  25:  }

The only change I’ve made is that, on line #24, I added a property for the Model which I typed as dynamic. That is what makes it possible for me to simply refer to @Model in the razor template I showed above. So the final step is that I need a way to pass in that model to my template. Well, with the WCF bits available from CodePlex, this is now quite easy to do. Ultimately, I need to create my own HTML Processor to hook into the pipeline.

   1:  public class RazorHtmlProcessor : MediaTypeProcessor
   2:  {
   3:      public RazorHtmlProcessor(HttpOperationDescription operation, MediaTypeProcessorMode mode)
   4:          : base(operation, mode)
   5:      {
   6:      }
   8:      public override IEnumerable<string> SupportedMediaTypes
   9:      {
  10:          get { yield return "text/html"; }
  11:      }
  13:      public override void WriteToStream(object instance, System.IO.Stream stream, Microsoft.Http.HttpRequestMessage request)
  14:      {
  15:          var templateManager = new TemplateEngine();
  16:          var currentTemplate = templateManager.CreateTemplate(instance.GetType());
  18:          // set the model for the template
  19:          currentTemplate.Model = instance;
  20:          currentTemplate.Execute();
  21:          using (var streamWriter = new StreamWriter(stream))
  22:          {
  23:              streamWriter.Write(currentTemplate.Buffer.ToString());
  24:          }
  25:          currentTemplate.Buffer.Clear();
  26:      }
  28:      public override object ReadFromStream(System.IO.Stream stream, Microsoft.Http.HttpRequestMessage request)
  29:      {
  30:          throw new NotImplementedException();
  31:      }
  32:  }

Notice that all I need to do on line #10 is to specify which media types I can respond to.  Then I simply have a stream I can write directly to in the WriteToStream() method. This allows me to now request “text/html” and you can see I now get HTML returned from WCF:


I’ve excluded the code of the TemplateEngine in this post in the interest of brevity. It closely matches the sample by Andrew Nurse – I just had to make a few tweaks to enable the ability to bind to dynamic types as well as to be able to read the Contact.cshtml file from disk. My complete code sample can be downloaded here (the contact manager parts are copy/paste from the sample available on the WCF CodePlex site).  It is far from Production-ready (e.g., it’s currently hard-coded to read only the Contact.cshtml file but could easily be extended UPDATE: I’ve updated code so engine now dynamically loads template based on type; for example, for a Contact object, it will find Contact.cshtml, borrowing the concept from MVC EditorTemplates) but this gives you a glimpse of the types of things that are now possible when combining the WCF HTTP library with a custom-hosted Razor view engine!

posted on Wednesday, November 17, 2010 8:34 AM Print
# re: Combine WCF MediaTypeProcessors with a Custom Razor Host
11/17/2010 2:04 PM

Again way far ahead of the Curve !!!

Indeed a excellent feature and the simplicity with WCF is awesome.

Thank you for this simplified write up. Very useful as always.


# re: Combine WCF MediaTypeProcessors with a Custom Razor Host
Glenn Block
11/18/2010 2:01 AM
Uh thanks, I need to go to the hospital now as I just blew a gasket in my brain. :-)

This is really awesome stuff Steve. Thanks for all your work. I was just talking to my boss about the lack of blog posts. This rocks!
# re: Combine WCF MediaTypeProcessors with a Custom Razor Host
11/27/2010 7:59 AM
Thanks for summarising this .NET stuff for us Steve. I don't use .NET alot, and MS seem to be always doing a lot to the framework, so it's nice to have a place where I can catch up on it, in a non-sales pithy, brief way!
# Error while copying content to a stream.
Mahesh Kshirsagar
2/9/2011 2:44 PM

I am getting this error using above sample.
I am using different class (with just 2 properties, FirstName and LastName) instead of ContactResource class as shown in the exaample.

{"Error while copying content to a stream."}

Exact Location is in class MediaTypeProcessor.cs at

this.WriteToStream(instance, s, request);
s.Position = 0;

Until execution reaches in RazorHtmlProcessor.cs

// set the model for the template
currentTemplate.Model = instance;
using (var streamWriter = new StreamWriter(stream))

everything is fine. i.e.CurrentTemplate.Buffer.Tostring actually has correct HTML output.

But then we execution reached in class HttpMessageEncoderFactory.cs
at this location
byte[] messageBytes = response.Content.ReadAsByteArray();

I start getting this error.

Is it just preview thing or am I missing something?

# re: Combine WCF MediaTypeProcessors with a Custom Razor Host
2/13/2011 6:14 AM
@Mahesh - Hard to know without seeing your sample. Did you change any of the code other than the 2 properties?
# re: Combine WCF MediaTypeProcessors with a Custom Razor Host
2/14/2011 3:33 PM
No changes(except structuring the app in my way)

I have uploaded the code at -
# re: Combine WCF MediaTypeProcessors with a Custom Razor Host
3/3/2011 3:22 AM
@Mahesh - You are using a different version of the Microsoft.ServiceModel.WebHttp assembly than I am. The ContactManagerConfiguration that I have inherits from the HostConfiguration class. The configuration class you have inherits from HttpHostConfiguration. Plus, keep in mind these are early bits and the WCF team *might* still have a bug or two.
# re: Combine WCF MediaTypeProcessors with a Custom Razor Host
Mohan Sundaram
6/1/2011 4:41 AM
Very interesting post, Steve.

But have you tried fetching the HTML from a browser, rather than Fiddler? This works for some browsers but not for others, for instance Chrome.

The reason being the Content-type from the service is set as application/xml. I've fixed this by fiddling with settings in IIS, but do you know how the service itself can be coaxed to provide text/html?

# re: Combine WCF MediaTypeProcessors with a Custom Razor Host
6/8/2011 1:15 AM
@Mohan - Chrome sends at Accept header of: "Accept: application/xml,application/xhtml+xml,text/html" so this should work just fine. Also, in the example above I set my html processor to only respond to "text/html" but you can give a list of values that your media type processor can respond to.

Post Comment

Title *
Name *
Comment *  

View Steve Michelotti's profile on LinkedIn

profile for Steve Michelotti at Stack Overflow, Q&A for professional and enthusiast programmers

Google My Blog

Tag Cloud