Skip to main content

OpenRasta vs WCF for RESTful Services

 

Not long ago I discovered OpenRasta. If you’re not familiar with it it’s described as a “resource-oriented framework for .NET enabling easy ReST-ful development of websites and services”.

After reading Rails 3 in a Nutshell I started looking at .NET a bit differently and have started being envious of the simplicity of Rails. When it comes to REST the ROR guys have definitely approached it the right way and it is baked right into the Rails framework.

When it comes to .NET there are a few different approaches you can take to create RESTful services.

  • ASP.NET MVC
  • WCF
  • OpenRasta
  • Other MVC Frameworks
  • Standard HTTP Handlers

In this post I’m going to cover how you can implement such a service using WCF and OpenRasta.

The goal is to expose a Product as JSON and XML using a RESTful uri.

product/1

WCF Approach

First let’s have a look at how to do this in WCF

Project Structure

Just create a standard WCF Service Application Project

wcfproject

DataContract

The first thing we have to do is create a DataContract which is just a Data Transfer Object that you want to be exposed by the web service.

    [DataContract]
    public class Product
    {
        [DataMember]
        public int Id { get; set; }

        [DataMember]
        public string Name { get; set; }
    }

You have to annotate the class with the DataContract attribute and properties with the DataMember attribute.

Service Contract

Now we have to define our Service Contract.

    [ServiceContract]
    public interface ICatalogService
    {
        [OperationContract]
        [WebGet(UriTemplate = "product/{id}", ResponseFormat = WebMessageFormat.Json)]
        Product GetProductById(string id);

    }

The important part here is the WebGet attribute. The UriTemplate specifies the route which you can access the Resource on and the ResponseFormat specifies the format or Content-Type to return the resource as, you can choose from Json or XML.

Having to limit to a single Content-Type is already a serious limitation and the UriTemplate being an attribute property makes it hard to change this route easily.

Also notice that the Id argument is a string, this is deliberate as the UriTemplate only supports having path segments of type string. If you try otherwise you will see an exception similar to below.

Operation 'GetProductById' in contract 'ICatalogService' has a path variable named 'id' which does not have type 'string'.  Variables for UriTemplate path segments must have type 'string'.

Service Implementation

Next we go to the Service implementation, this is pretty standard.

    [AspNetCompatibilityRequirements(RequirementsMode= AspNetCompatibilityRequirementsMode.Allowed)]
    public class CatalogService : ICatalogService
    {
       
        public Product GetProductById(int id)
        {
            var product = new Product { Name = "WCF", Id = 1 };

            return product; 
        }

     }

 

The only difference here from a standard service implementation is the use of the AspNetCompatibilityRequirements attribute on the class.

Web.Config

The only additional config required is the standardEndpoints configuration. The full config is below.

 <system.serviceModel>
    <standardEndpoints>
      <webHttpEndpoint>
        <standardEndpoint defaultOutgoingResponseFormat="Json" name="" helpEnabled="true" automaticFormatSelectionEnabled="true" />
      </webHttpEndpoint>
    </standardEndpoints>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <serviceMetadata httpGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>

 

Consuming the Service

For the service to return JSON you have to specify in the Content-Type as "application/json” in the HTTP Header, for XML use application/xml.

You can consume using URI http://myrestsite.com/CatalogService.svc/product/1

Observations

Ok well that wasn’t so bad, however I’m sure you’ve already identified a few limitations.

  • Inflexible routing options, only one Uri per method
  • Only able to return XML or JSON
  • Heavy use of Attributes

 

OpenRasta Approach

OpenRasta deal with Resources, Handlers and Views, but we aren’t concerned with Views in this post.

Handlers
”Handlers are the objects responsible to act upon resources through the HTTP uniform interface and will always get called first. They're the equivalent of Controllers in other MVC frameworks.”


Resources
”Your resources are what you expose on various Uris. In OpenRasta, each thing you want to expose on the web needs to have a Resource class associated with it.”

 

Project Structure

To host OpenRasta you need to create a standard Web Application project but your Resources and Handlers can be contained in a standard Class Library project.

After installing OpenRasta you’ll need to add references to the following DLLs:

  • OpenRasta.dll
  • OpenRasta.Codecs.WebForms.dll
  • OpenRasta.Hosting.AspNet.dll

The project structure is very simple, you can split it into Handlers and Resources as shown below.

openrastaproject

Resource

The Resource or DTO is just a standard POCO.

   public class Product
   {
       public int Id { get; set; }

       public string Name { get; set; }
   }

Notice there’s no base class to inherit or any attributes. This is important as it makes it very easy to utilise Classes that you already have defined.

Handler

Handlers are equivalent to MVC Controllers or compared with WCF it’s the Service implementation.

    public class ProductHandler
    {
        public object Get(int id)
        {
            var product = new Product {Name = "OpenRasta", Id = 1};

            return product;
        }
    }

Again no base class or attributes required.

OpenRasta Config

One of the great things about OpenRasta is that the Configuration of how the Resources are accessed is completely decoupled from the implementation. The configuration has a nice fluent interface for configuring Handlers and Resources.

You can create a class with any name and implement the OpenRasta.Configuration.IConfigurationSource interface

   public class OpenRastaConfig : IConfigurationSource
   {
       #region IConfigurationSource Members

       public void Configure()
       {
           using (OpenRastaConfiguration.Manual)
           {
               ResourceSpace.Has.ResourcesOfType<Product>()
                   .AtUri("/product/{id}")
                   .HandledBy<ProductHandler>()
                   .AsJsonDataContract()
                   .And
                   .AsXmlDataContract();
           }
       }

       #endregion
   }

 

.AtUri specifies the Uri you can use to access the Resource. It’s also possible to have multiple Uris for the same resource.

                    .AtUri("/product/{id}")
                    .And
                    .AtUri("/products/{id}")

.HandledBy<ProductHandler> specifies the Handler to use.

.AsJsonDataContract() tells OpenRasta you want to expose the resource as Json

.AsXmlDataContract() tells OpenRasta you want to expose the resource as Xml

Web.Config

There is a little bit of Web.Config configuration to be done as well, this is all you need:

<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
    <httpHandlers>
      <add verb="*" path="*.rastahook" type="OpenRasta.Hosting.AspNet.OpenRastaHandler, OpenRasta.Hosting.AspNet"/>
    </httpHandlers>
    <httpModules>
      <add name="OpenRastaModule" type="OpenRasta.Hosting.AspNet.OpenRastaModule, OpenRasta.Hosting.AspNet"/>
    </httpModules>
  </system.web>
  <system.webServer>
    <validation validateIntegratedModeConfiguration="false"/>
    <modules>
      <add name="OpenRastaModule" type="OpenRasta.Hosting.AspNet.OpenRastaModule, OpenRasta.Hosting.AspNet"/>
    </modules>
    <handlers>
      <add name="OpenRastaHandler" verb="*" path="*.rastahook" type="OpenRasta.Hosting.AspNet.OpenRastaHandler, OpenRasta.Hosting.AspNet" />
    </handlers>
  </system.webServer>
</configuration>

Consuming the Service

As with WCF you need to specify the correct Content-Type to get the format you desire.

You can consume using a URI like http://myrestsite.com/product/1 or http://myrestsite.com/products/1

Observations

All in all OpenRasta is a nicer development experience and is more closely tied to the definition of REST. It is fully extensible and allows to return a Resource in any Format, including an HTML View.

 

Conclusion

I’ve only touched on a very basic use of OpenRasta, it has tons more functionality which makes developing RESTful services a breeze and also stacks up as a very good MVC framework if you’re having issues with the ASP.NET implementation. It has pretty good documentation and a strong community around it.

Check out the Comparisons table for a round up of features.

IMO doing REST in WCF just doesn’t seem very intuitive to me and is much less flexible especially when you dive deep into using HTTP Status Codes and HTTP Verbs.

If you have a requirement to develop a RESTful service instead of defaulting to WCF I urge you consider OpenRasta instead.

Till next time.

Popular posts from this blog

ASP.NET MVC Release Candidate - Upgrade issues - Spec#

First of all, great news that the ASP.NET MVC Release Candidate has finally been released.  Full credit to the team for the hard work on this.  You can get the download here  However this is the first time I have had upgrade issues.  Phil Haack has noted some of the issues here   If like me you have lot's of CTP's and Add-Ins then you might experience some pain in Uninstalling MVC Beta on Vista SP1  This is the list of Add-Ins / CTP's I had to uninstall to get it to work  Spec# PEX Resharper 4.1  Sourcelinks ANTS Profiler 4   Can't say I'm too impressed as it wasted over an hour of my time.  As it turned out Spec# turned out to be the offending culprit, it's forgiveable to have issues with a third party product but a Microsoft one? Guess no-one on the ASP.NET team has Spec# installed. 

Freeing Disk Space on C:\ Windows Server 2008

  I just spent the last little while trying to clear space on our servers in order to install .NET 4.5 . Decided to post so my future self can find the information when I next have to do this. I performed all the usual tasks: Deleting any files/folders from C:\windows\temp and C:\Users\%UserName%\AppData\Local\Temp Delete all EventViewer logs Save to another Disk if you want to keep them Remove any unused programs, e.g. Firefox Remove anything in C:\inetpub\logs Remove any file/folders C:\Windows\System32\LogFiles Remove any file/folders from C:\Users\%UserName%\Downloads Remove any file/folders able to be removed from C:\Users\%UserName%\Desktop Remove any file/folders able to be removed from C:\Users\%UserName%\My Documents Stop Windows Update service and remove all files/folders from C:\Windows\SoftwareDistribution Deleting an Event Logs Run COMPCLN.exe Move the Virtual Memory file to another disk However this wasn’t enough & I found the most space was

Consuming the SSRS ReportExecutionService from a .NET Client

  I’ve just finished writing a nice wrapper which internally calls the SSRS ReportExecutionService to generate reports. Whilst it was fairly simple to implement there has been some major changes between 2005 and 2008 and the majority of online and documentation is based on the 2005 implementation. The most important change is that the Report Server and Report Manager are no longer hosted in IIS which will be a welcomed change to Sys Admins but makes the security model and hosting model vastly different. So far I’ve yet to figure out how to allow Anonymous Access, if anyone knows how to do this leave a comment and it will be most appreciated. Getting Started To get started you’ll want to add a service reference to http://localhost/ReportServer_SQL2008/ReportExecution2005.asmx where ReportServer_SQL2008 is the name you configure in the Reporting Services Configuration Manager. The Web Application files are located in C:\Program Files\Microsoft SQL Server\MSRS10.SQL2008\R