Posts
203
Comments
1119
Trackbacks
51
November 2010 Entries
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:

contact-xml

 

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

contact-json

 

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

contact-png

 

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; }
   5:   
   6:      public TemplateBase()
   7:      {
   8:          Buffer = new StringBuilder();
   9:          Writer = new StringWriter(Buffer);
  10:      }
  11:   
  12:      public abstract void Execute();
  13:   
  14:      public virtual void Write(object value)
  15:      {
  16:          WriteLiteral(value);
  17:      }
  18:   
  19:      public virtual void WriteLiteral(object value)
  20:      {
  21:          Buffer.Append(value);
  22:      }
  23:   
  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:      }
   7:   
   8:      public override IEnumerable<string> SupportedMediaTypes
   9:      {
  10:          get { yield return "text/html"; }
  11:      }
  12:   
  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());
  17:   
  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:      }
  27:   
  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:

contact-html

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 | Comments (9)
PDC10 Reston Links

Thanks to everyone who attended my session at PDC10 Reston on Friday. The links to the various code and resources I using during the presentation can be found here:

PowerPoint and Main Solution

Visual Studio Async CTP

WCF Web APIs

Posted On Monday, November 15, 2010 10:03 AM | Comments (0)
Create a FULL Local NuGet Repository with PowerShell

UPDATE: with the release of NuGet 1.0 RTM, this script has some breaking changes. For an updated version, see this post by Jon Galloway: Downloading a local NuGet repository with PowerShell.

NuGet is simply awesome. Despite its relative infancy, it has already established itself as the standard for .NET package management. You can easily add packages from the public feed or even from a local directory on your machine. Phil Haack already has an excellent post describing how you set up a local feed. His post does a great job of explaining *how* to set up the feed, but how do you get packages (that you didn’t create locally) to put in there in the first place? One way is to simply install a package and then grab the *.nupkg file locally and then copy/paste it into whatever folder you’ve designated as your local NuGet feed. For example, if I’ve added the AutoMapper package, I can just grab it from here:

local nuget automapper

But what if I want to grab ALL of the packages from the local feed and store them all locally in a single directory? Certainly, this copy/paste process is way to manual of a process. Fortunately, the OData feed for NuGet tells you all you need to know.

nugetfeed

 

Notice how the <content> tag shows me the URI that I need to hit in order to download the file? That makes life easy. Now all we need is a few lines of PowerShell to put everything in a single local directory:

   1:  $webClient = New-Object System.Net.WebClient
   2:  $feed = [xml]$webClient.DownloadString("http://feed.nuget.org/ctp2/odata/v1/Packages")
   3:  $destinationDirectory = "C:\development\LocalNuGetTest"
   4:   
   5:  $records = $feed | select -ExpandProperty feed | select -ExpandProperty entry | select -ExpandProperty content
   6:              
   7:  for ($i=0; $i -lt $records.Length; $i++) {
   8:      $url = $records[$i].src
   9:      $startOfQuery = $url.IndexOf("?p=") + 3
  10:      $fileName = $url.Substring($startOfQuery, $url.Length - $startOfQuery)
  11:      $fullPath = ($destinationDirectory + "\" + $fileName)
  12:      $webClient.DownloadFile($records[$i].src, ($destinationDirectory + "\" + $fileName))
  13:  }            

I specify my destination directory on line 3. Then I expand the XML elements into an object that PowerShell understands. After that it’s a simple matter of string parsing and downloading the files with the WebClient.

Now that you have all the packages locally, you can work offline even when you don’t have access to the public feed.

Posted On Wednesday, November 10, 2010 3:34 AM | Comments (2)
The Time is Now to Start Checking out the WCF Web APIs

Over the last 3 years, Microsoft has slowly but surely been embracing REST as a programming model for the web in WCF. .NET 3.5 SP1 introduced some REST constructs allowing us to invoke WCF services with HTTP GET/POST/PUT/DELETE verbs in conjunction with UriTemplates. The REST Starter Kit (RSK) was then introduced on CodePlex and this provided many great features including an HTML help page, request interceptors, an HTTP client library, and more. Then WCF 4 was released and some of the features in the REST Starter Kit (e.g., automatic help page) were moved into the actual framework. At this point WCF has gotten *much* easier to work with and I have blogged in the past showing how simple it is to stand up RESTful services with no svc file and no config. This makes the experience just as easy as building services in MVC but you get richer functionality than MVC provides out of the box with automatic help page and automatic format selection (xml, json, etc.).

At PDC10 last week, the WCF web http team showed that this story is only going to get better – much better. In the presentation “Building Web APIs for the Highly Connected Web”, Glenn Block (currently a PM on the WCF team but you might know him from his work with MEF) showed numerous examples of the types of things that we can be expecting to be released in the future. And these features are available right now for you to start playing with – just head over the the WCF site on CodePlex to download the bits. Go ahead – do it now. I have the pleasure of being a member of an HTTP WCF Advisors group organized by Glenn and the one thing I can definitively tell you is that Microsoft is listening. Yes, in the past Microsoft sometimes added features to the .NET framework that we as developers didn’t always find useful or simple enough to use. But that is not the case with the WCF HTTP team – if you have a feature you are interested in, go tell them!

One of the key features you’ll find in the latest bits are Processors. When the RSK was introduced, it included RequestInterceptors which were incredibly helpful for intercepting the request to get at headers and content of the current request through the HttpRequestMessageProperty type. However, the RequestInterceptors feature did *not* make it into WCF 4. With the introduction of Processors you’ll be easily able to do everything you could do with RSK and more. One of the things that is very easy to do with Processors is to manipulate the format of your requests. For example, in WCF 4 with webHttp you get automatic format selection (between XML/JSON) by adding this to your web.config file:

   1:  <system.serviceModel>
   2:    <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
   3:    <standardEndpoints>
   4:      <webHttpEndpoint>
   5:        <standardEndpoint name="" helpEnabled="true" automaticFormatSelectionEnabled="true"/>
   6:      </webHttpEndpoint>
   7:    </standardEndpoints>
   8:  </system.serviceModel>

Notice on line #5 above, we turn on automatic format selection. This allows us to pick either XML or JSON by specifying the appropriate value in the Accept header. However, with Processors now, you don’t even need this config – in fact, you don’t need any XML configuration at all. Instead you can create your own configuration class in C# and specify the JsonProcessor there:

   1:  public class MyConfiguration : HostConfiguration
   2:  {
   3:      public override void RegisterRequestProcessorsForOperation(HttpOperationDescription operation, IList<Processor> processors, MediaTypeProcessorMode mode)
   4:      {
   5:          processors.Add(new JsonProcessor(operation, mode));
   6:      }
   7:   
   8:      public override void RegisterResponseProcessorsForOperation(HttpOperationDescription operation, IList<Processor> processors, MediaTypeProcessorMode mode)
   9:      {
  10:          processors.Add(new JsonProcessor(operation, mode));
  11:      }
  12:  }

You can then register this configuration during application start up in your global.asax like this:

   1:  RouteTable.Routes.AddServiceRoute<FooResource>("foo/", new MyConfiguration());

There is a “Contact Manager” sample available in the download that shows this functionality. The ability to avoid XML configuration is nice but it’s really only part of the story. The real beauty of this is that, since the Processors are extensible, you can add your own processor for ANY format that you want to support from your service – e.g,. xml, json, atom pub, html, png, plain text, etc,. etc.

One of the things that I was most disappointed in when I saw what was put into WCF 4 was the lack of the HttpClient which was introduced in the RSK. Fortunately, it is now back and enhancements are actively being worked on!

Given the huge popularity of jQuery, there is also direct support for sending JSON to the server using C# dynamic typing so you can work with JSON on the server similar to dynamic languages like Ruby.

There is also much more on the horizon – much of which hasn’t even been publicly announced yet. This is the time to start checking out what Microsoft is doing to enable HTTP in WCF. Go to http://wcf.codeplex.com/ now – download the bits and tell the team what you think.

Posted On Sunday, November 7, 2010 10:14 PM | Comments (9)
CMAP Code Samples

Thanks to everyone who attended my Entity Framework 4 presentation at CMAP last night. The code samples and PowerPoint can be downloaded here. The code samples include the Code First Optimistic Concurrency demo that I did not have time to show. More information can be found on that here.

Posted On Wednesday, November 3, 2010 11:19 AM | Comments (5)

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