Using Google Protocol Buffers Hypermedia Type with WCF RESTful Services: A media type processor sample

Protocol Buffers is language neutral format for serializing structured data in a very optimal format. You can think about protocol buffers as XML or JSON but lighter and smaller. This format its widely used at Google to exchange data between different systems.

Given its optimal representation of structured data, protocol buffers it’s a great option for representing data processed by RESTful services. To follow the principles of REST, protocol buffers should be a represented as a new hypermedia type. In the current version of Windows Communication Foundation (WCF), incorporating a new media type requires a significant amount of effort. Fortunately, the new version of the WCF HTTP stack makes media type a first class citizen of the WCF programming model. You can find more details about this new stack on Glenn Block’s weblog.

The following section will illustrate how to leverage Google’s protocol buffers as a native media type in the WCF stack.

Implementing a protocol buffers media type processor with WCF-HTTP

The new WCF HTTP programming model abstracts the processing of a hypermedia type by using a component known as media type processors. Essentially, media type processors are represented by classes that inherit from the MediaTypeProcessor class and are invoked by the WCF runtime to handle the serialization incoming and outgoing messages in a specific media type representation.

The first important thing we need to figure out in order to implement a protocol buffers media type processors is the correct API to use. From the existing implementations, I believe the Marc Gravell’s implementation provides the cleanest programming model. Serializing an object into protocol buffers is as simple as illustrated in the following code.

   1: MemoryStream stream= new MemoryStream();
   2: SampleObj obj= new SampleObj();
   3: Serializer.Serialize(stream, obj);

We can leverage the same technique to implement a protocol buffers media type processor as highlighted in the following code:

   1: public class ProtocolBufferProcessor: MediaTypeProcessor
   2:     {
   3:  
   4:         public ProtocolBufferProcessor(HttpOperationDescription operation, 
   5:                                        MediaTypeProcessorMode mode)
   6:             : base(operation, mode)
   7:         {
   8:         }
   9:  
  10:         public override IEnumerable<string> SupportedMediaTypes
  11:         {
  12:             get
  13:             {
  14:                 yield return "application/x-protobuf";
  15:             }
  16:         }
  17:  
  18:          public override object ReadFromStream(Stream stream, 
  19:                                                HttpRequestMessage request)
  20:          {
  21:              throw new NotImplementedException();
  22:          }
  23:  
  24:          public override void WriteToStream(object instance, Stream stream,
  25:                                             HttpRequestMessage request)
  26:          {
  27:              Serializer.Serialize(stream, instance);
  28:              stream.Position = 0;
  29:          }
  30:  
  31:     }

As illustrated above, the WriteToStream operation handles the serialization of the .NET objects into the protocol buffers format.

Let’s explore how to use our media type processor with the following WCF service:

   1: [ServiceContract]
   2: [AspNetCompatibilityRequirements(RequirementsMode 
   3: = AspNetCompatibilityRequirementsMode.Allowed)]
   4: public class AccountResource
   5: {
   6:     private List<Account> accounts = new List<Account>() { 
   7:         new Account(){AccountNumber= "12345", Id= 1, 
   8:                      Balance= 10000000,
   9:                       Description= "Sample Account"},
  10:         new Account(){AccountNumber= "12345", Id= 1, 
  11:                      Balance= 10000000,
  12:                       Description= "Sample Account"},
  13:         new Account(){AccountNumber= "12345", Id= 1, 
  14:                      Balance= 10000000,
  15:                       Description= "Sample Account"}};
  16:  
  17:     public AccountResource()
  18:     { }
  19:  
  20:     [QueryComposition]
  21:     [WebGet(UriTemplate= "")]
  22:     public Account GetAccounts()
  23:     {
  24:         return accounts.AsQueryable<Account>();
  25:     }
  26:  
  27: }
  28:  
  29: public class Account
  30: {
  31:     private string accountNumber;
  32:     private int id;
  33:     private string description;
  34:     private double balance;
  35:  
  36:     public string AccountNumber
  37:     {
  38:         get { return accountNumber; }
  39:         set { accountNumber = value; }
  40:     }
  41:  
  42:     public int Id
  43:     {
  44:         get { return id; }
  45:         set { id = value; }
  46:     }
  47:  
  48:     public string Description
  49:     {
  50:         get { return description; }
  51:         set { description = value; }
  52:     }
  53:  
  54:     public double Balance
  55:     {
  56:         get { return balance;}
  57:         set{balance= value;}
  58:     }
  59: }
  60:  

We can inject the protocol buffers media processor into the WCF runtime by implementing the following host configuration as illustrated in the following code.

 

   1: public class AccountResourceConfiguration : HttpHostConfiguration, 
   2:                                            IProcessorProvider
   3: {
   4:     public void RegisterRequestProcessorsForOperation(
   5:                               HttpOperationDescription operation,
   6:                               IList<Processor> processors,
   7:                               MediaTypeProcessorMode mode)
   8:     {
   9:         
  10:         processors.Add(new JsonProcessor(operation, mode));
  11:         processors.Add(new FormUrlEncodedProcessor(operation, mode));
  12:          
  13:     }
  14:  
  15:     public void RegisterResponseProcessorsForOperation(
  16:                                  HttpOperationDescription operation,
  17:                                  IList<Processor> processors,
  18:                                  MediaTypeProcessorMode mode)
  19:     {
  20:         processors.Add(new JsonProcessor(operation, mode));
  21:         processors.Add(new ProtocolBufferProcessor(operation, mode));
  22:     }
  23: }

We can initialize the host configuration in the route tables structure as shown in the following code.

   1: public class Global : System.Web.HttpApplication
   2:    {
   3:  
   4:        protected void Application_Start(object sender, EventArgs e)
   5:        {
   6:            var configuration = new AccountResourceConfiguration();
   7:            RouteTable.Routes.AddServiceRoute<AccountResource>("accounts", 
   8:                                      new AccountResourceConfiguration());
   9:        }
  10:  
  11:        
  12:    }

At this point, our WCF service is ready to leverage the protocol buffers hypermedia format. The client should indicate the expected media type by using the Accept HTTP header as shown in the following code.

GET /ProtocolBuffers/accounts">/ProtocolBuffers/accounts">/ProtocolBuffers/accounts">http://<service endpoint>/ProtocolBuffers/accounts HTTP/1.1
User-Agent: Fiddler
Accept: application/x-protobuf
Host: localhost:8081

The response message using the protocol buffers format looks like the following:

HTTP/1.1 200 OK
Cache-Control: private
Content-Length: 108
Content-Type: application/x-protobuf
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Fri, 21 Jan 2011 04:15:32 GMT

"
12345Sample Account!?????cA
"
12346Sample Account!?????9?A
"
12347Sample Account!???`P??A

 

Even though Google’s protocol buffer is nowhere near in popularity as other serialization formats such as XML or JSON it is, undoubtedly, an very efficient hypermedia type to use in your RESTful services.

1 Comment

Comments have been disabled for this content.