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

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

3 Reasons Why Progressive Web Apps (PWAs) Won’t Replace Native Apps

Many people believe Progressive Web Apps (PWAs) are the future of the mobile web, but in my opinion, PWAs are not a replacement for native mobile apps. Here are three reasons why: 1. Native mobile apps provide a smoother & faster experience  Mobile websites, progressive or otherwise are slower and not as smooth. 90% of the time spent is spent using apps vs the browser . The single most significant contributing factor to a smooth experience on mobile is the speed of the network and latency of the data downloaded and uploaded. When you visit websites on desktop or mobile, there is a lot of third-party code/data that gets downloaded to your device, which more often than not has zero impact on the user experience. This includes: CSS (Cascading Style Sheets) JavaScript Ad network code Facebook tracking code Google tracking code The median number of requests a mobile website makes is a shocking  69 . On the other hand, native apps only get the data that is requi

Unit Testing Workflow Activities in .NET 4.0

  Recently during a catch up with my buddy Keith Patton I was (as I tend to do) singing the praises of the Workflow in .NET 4.0. The all important question about Unit Testing support was raised, I tried as best as I could to explain the new In and Out Arguments but I didn’t feel I was convincing enough, so I though I would clarify with a blog post. If you developed Workflows in .NET 3.5 then you will be well aware of the lack of Unit Test support which was due to many reasons but mostly in part to the complex Workflow hosting environment. When moving to .NET 4.0 Workflow Foundation from .NET 3.5 it pays to be conscious of that fact that there is no longer a distinction between Activities and Workflows. Everything derives from the System.Activities.Activity class. So the definition of a Workflow is just a collection of of 1 or more Activities. I have designed a very simple Rental Car Activity which takes the an Applicants age as the input and outputs a True or False depending o