Monday, 19 October 2015

WCF REST API CORS enabled extension

The REST Apis are designed to work with Web i.e. a network of different connect domain that works together by sharing resources. But in today’s world we have all modern browsers which are highly supporting the CORS. Those who don’t know about CORS can learn about it here.

In a simple language, CORS is simply allowing other domain to request for a resource hosted in a another domain. So e.g. If a image is hosted on SiteA.com and Siteb.com wants to access this image to display in one of his page then SiteA.com has to allow it. The browser which is accessing SiteB.com will know by reading the response header which are coming after making a request to SiteA.com. So if it has CORS header information then the request can be fetcher other wise browser will simply reject the response without displaying any specific error.

Sample Response headers of CORS from SiteA.com:
Access-Control-Allow-Origin: http://SiteB.example
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER
Access-Control-Max-Age: 1728000

You visualize the above situation something like below though it’s not a complete coverage of whole CORS concept but it will get you going.
Example with NO CORS

Example with CORS support

Know more about the Server side CORS and Client CORS. The  same scenario applies when a cross domain REST Api request is made. So Your WCF REST api service should server the response with CORS headers. The feature is not supported out of box but WCF provides a lot of extensibility points. So you can extend/create a new behavior and plug it in to have your WCF REST Api CORS enabled.
So conceptually you can develop a new Endpoint behaviorEndpoint behavior with a custom message inspectormessage inspector that will inject the CORS headers settings in the Response you’re the requesting browser doesn’t deny it.
Here’s how the custom message inspector would look like:

using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using System.Text;
using System.Threading.Tasks;
 
namespace WebHttpBehaviorExtensions.Cors
{
    public class CustomHeaderMessageInspector : IDispatchMessageInspector
    {
        Dictionary<string, string> requiredHeaders;
        public CustomHeaderMessageInspector(Dictionary<string, string> headers)
        {
            requiredHeaders = headers ?? new Dictionary<string, string>();
        }
 
        public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
        {
            return null;
        }
 
        public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
        {
            var httpHeader = reply.Properties["httpResponse"] as HttpResponseMessageProperty;
            foreach (var item in requiredHeaders)
            {
                httpHeader.Headers.Add(item.Key, item.Value);
            }
        }
    }
}



Message inspector is actually that adds the headers into response with method BeforeSendReply. Now we have to inject this custom message inspector object into collection of default message inspector. To do that we have create a new class implementing IEndpointBehavior interface also we’ll be using the same class to extend the base class BehaviorExtensionElement(This would help injecting the behavior from configuration.)



using System;
using System.Collections.Generic;
using System.ServiceModel.Configuration;
using System.ServiceModel.Description;
 
namespace WebHttpBehaviorExtensions.Cors
{
    class EnableCorsBehavior : BehaviorExtensionElement, IEndpointBehavior
    {
        public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        { }
 
        public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
        { }
 
        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
        {
            var requiredHeaders = new Dictionary<string, string>();
 
            requiredHeaders.Add("Access-Control-Allow-Origin", "*");
            requiredHeaders.Add("Access-Control-Request-Method", "POST,GET,PUT,DELETE,OPTIONS");
            requiredHeaders.Add("Access-Control-Allow-Headers", "X-Requested-With,Content-Type");
 
            endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new CustomHeaderMessageInspector(requiredHeaders));
        }
 
        public void Validate(ServiceEndpoint endpoint) { }
 
        public override Type BehaviorType
        {
            get { return typeof(EnableCorsBehavior); }
        }
 
        protected override object CreateBehavior()
        {
            return new EnableCorsBehavior();
        }
    }
}


That’s it. Now to show you the configuration settings I’ll just put the parts which are needs to be updated with this new behavior setting. In configuration under <service.model> add following endpoint behavior:
Define the Extension behavior first


<extensions>
      <behaviorExtensions>
        <add name="corsBehavior" type="WebHttpBehaviorExtensions.Cors.EnableCorsBehavior, WebHttpBehaviorExtensions, Version=1.0.0.0, Culture=neutral" />
      </behaviorExtensions>
</extensions>

Add behavior


<behaviors>
     <endpointBehaviors>
       <behavior name="webHttpServiceBehavior">
         <corsBehavior />
         <webHttp/>
       </behavior>
     </endpointBehaviors>
</behaviors>
Now add the custom behavior settings to your endpoint in <services> section:


<services>
  <service name="WcfWebHttpIISHostingSample.TestService" behaviorConfiguration="ServiceBehavior">
    <endpoint binding="webHttpBinding" contract="WcfWebHttpIISHostingSample.ITestService" behaviorConfiguration="webHttpServiceBehavior" />
  </service>
</services>

That’s it. Now you can test your settings by deploying the WCF REST service to IIS and when making a request press F12 and look for Network request and response Headers. You can also use tools like `Fiddler` and `Chrome Post Master` to perform a Get/Post request and analyzing header.

This blog post is part of a Extension behavior library that I’m currently working on to provide a set of Regularly required feature which aren’t available out of the box. To download the Library via Nuget from here:
Download WebHttpBehaviorExtension Nuget

If you like to contribute or want to look at the source code. The complete source code is open source and hosted on Github.
image