Introducing WCF Web API

Introduction

WCF is a highly sophisticated technology built on the foundation of replaceable transport. It is optimised for complex scenarios however only a handful of developers ever need to deal with those scenarios.

Most developers care a lot about the reach of the application and one of the best and easiest ways to do this is by supporting HTTP. WCF has always supported HTTP since its inception however the support was far from ideal because it could never take full advantage of HTTP.

HTTP is very well understood technology. Nearly every connected device available today supports one or other form of HTTP. If you speak the language of the Web, almost every consumer can consume your application.

WCF Web API fully implements HTTP Specification. It is important to note that WCF Web API is built on top of existing WCF and not replacing the existing WCF as we have come to know.

HTTP Support in WCF

HTTP Support has been part of WCF as part of various HTTP bindings, 3.5 SP1 made it easy to consume the response in XML and JSON. However it has never supported the features that make HTTP really powerful like full access to request and response, caching etc. HTTP is extremely flexible in the sense that it allows the body of the message to be presented in thousands of formats. WCF Web API allows this nicely by providing classes where you can provide support for any format over HTTP.

Architecture

clip_image002

Fig 1.0 Architecture Diagram

WCF Web API hooks into the extensibility mechanism of WCF. At the top layer it consists of resource class which consist of set of operation which receives HTTP Request and return HTTP Response.

Once the request is initiated from the client, WCF intercepts the request and start processing, it goes through its usual channel pipeline and once request is received in the form of bytes from the transport layer, it is converted from bytes to HttpRequestMessage.

After creation, the HttpRequestMessage instance passes through a sequence of message handlers. Each one of these message handlers receives an HttpRequestMessage and returns an HttpResponseMessage asynchronously.

After all the message handlers are processed, the operation is dispatched by first selecting the operation based on the request method name and Uri.

The next processing phase is responsible for producing the parameter set required by the selected operation, from the request message. These parameters are produced by operation handlers. These operation handlers may also be used to perform other type of operation specific message processing.

Before the operation is called, a resource class instance is obtained.

At the topmost layer, the operation is invoked using the parameters computed by the operation handlers.

After the operation’s invocation, the output parameters pass through a sequence of response operation handlers.

Also, if the response message was not returned by the operation, it is created in this phase.

Finally, the response message flows down through the message handlers until being turned into a byte sequence and written into the transport layer

Examples of Use of HTTP Verbs with WCF Web API

1. “GET” Example

This example takes a single parameter and returns fully typed HTTPResponseMessage of type person with the use of verb “GET”. Please note the use of HTTP natively and passing the Status Code in the standard HTTP format.

1 [WebGet(UriTemplate = "{id}")] 2 public HttpResponseMessage<Person> Get(int id) 3 { 4 5 var person = _repository.Get(id); 6 var response=new HttpResponseMessage<Person>(null); 7 if (person==null) 8 { 9 response.StatusCode = HttpStatusCode.NotFound; 10 } 11 else 12 { 13 response.Content = new ObjectContent<Person>(person); 14 } 15 return response; 16 }

2. “PUT” Example

This example takes two parameters and demonstrates how you can use “PUT”

1 [WebInvoke(UriTemplate = "{id}", Method = "PUT")] 2 public HttpResponseMessage<Person> Put(int id, Person person) 3 { 4 Get(id); 5 _repository.Update(person); 6 return new HttpResponseMessage<Person>(person); 7 }

3. GET with Queryable” Example

This example demonstrates OData style querying capabilities. More specifically you can retrieve records, apply filtering and also order them.

1 [WebGet(UriTemplate = "")] 2 public IQueryable<Person> Get() 3 { 4 return _repository.GetAll().AsQueryable(); 5 }

You can write queries In the format like

http://localhost/oData.Web/people?$filter=Id%20eq%201

Components of WCF Web API

WCF Web API is divided into following sections

1. Media Type Formatters

MediaTypeFormatters enables content negotiation. I.e. it makes it easier to support other format besides XML & JSON. If you want a resource to represent via specific format say iCal, just author a formatter and plug it in the pipeline. Following example shows how to represent a resource in a JpgFormatter.

1 public class JpgFormatter : MediaTypeFormatter 2 { 3 4 public JpgFormatter() 5 { 6 SupportedMediaTypes.Add(new MediaTypeHeaderValue("image/jpg")); 7 } 8 9 protected override bool OnCanReadType(Type type) 10 { 11 return true; 12 } 13 14 protected override bool OnCanWriteType(Type type) 15 { 16 return (type == typeof(Person)); 17 } 18 19 20 public override object OnReadFromStream(Type type, Stream stream, 21 HttpContentHeaders contentHeaders) 22 { 23 throw new NotImplementedException(); 24 } 25 26 public override void OnWriteToStream(Type type, object value, 27 Stream stream, HttpContentHeaders contentHeaders, 28 System.Net.TransportContext context) 29 { 30 var person = value as Person; 31 if (person != null) 32 { 33 { 34 var path = string.Format(CultureInfo.InvariantCulture, @"{0}bin\Images\Image{1}.jpg", 35 AppDomain.CurrentDomain.BaseDirectory, (Convert.ToInt32(person.Id) % 3) + 1); 36 using (var fileStream = new FileStream(path, FileMode.Open)) 37 { 38 var bytes = new byte[fileStream.Length]; 39 fileStream.Read(bytes, 0, (int)fileStream.Length); 40 stream.Write(bytes, 0, (int)fileStream.Length); 41 } 42 } 43 } 44 } 45 46 }

2. Message Handlers

WCF Web API provides low level message handlers as a mechanism to provide the hook into the HTTP Message Pipeline. You can do things like auditing of messages, provide security mechanisms etc. Following shows you an example of Logging Channel which hooks into the pipeline and then writes messages to trace.

1 public class LoggingChannel:DelegatingChannel 2 { 3 public LoggingChannel(HttpMessageChannel handler):base(handler) 4 { 5 } 6 7 protected override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, 8 System.Threading.CancellationToken cancellationToken) 9 { 10 System.Diagnostics.Trace.TraceInformation("Begin Request: {0} {1}", request.Method, request.RequestUri); 11 return base.SendAsync(request, cancellationToken); 12 } 13 }

 

3. Operation Handlers

Operation Handlers provides mechanism to intercept request before and after an operation is invoked. You can provide multiple operation handlers for the same operation. You can also provide Operation Handler for either single operation or all operation if required.

1 public class OperationHandlerFactory:HttpOperationHandlerFactory 2 { 3 4 5 protected override Collection<.HttpOperationHandler> OnCreateRequestHandlers(ServiceEndpoint endpoint, 6 HttpOperationDescription operation) 7 { 8 9 var baseHandlers = base.OnCreateRequestHandlers(endpoint, operation); 10 if (operation.InputParameters.Any(p => p.Type == typeof(int))) 11 { 12 baseHandlers.Add(new CustomRequestHandler(operation.InputParameters.FirstOrDefault().Name)); 13 } 14 15 baseHandlers.Add(new ZipOperationHandler(operation.InputParameters.FirstOrDefault().Name)); 16 baseHandlers.Insert(baseHandlers.Count() - 1, 17 new ZipOperationHandler(operation.InputParameters.FirstOrDefault().Name)); 18 19 return baseHandlers; 20 21 } 22 23 protected override Collection<HttpOperationHandler> OnCreateResponseHandlers(ServiceEndpoint endpoint, 24 HttpOperationDescription operation) 25 { 26 var baseHandlers = base.OnCreateRequestHandlers(endpoint, operation); 27 28 baseHandlers.Add(new ZipOperationHandler(operation.InputParameters.FirstOrDefault().Name)); 29 if (operation.Name.Contains("Get")) 30 { 31 baseHandlers.Add(new ZipOperationHandler(operation.InputParameters.FirstOrDefault().Name)); 32 } 33 34 return baseHandlers; 35 } 36 37 }

1 public class CustomRequestHandler:HttpOperationHandler<HttpRequestMessage,int> 2 { 3 public CustomRequestHandler(string outputParameterName) : base(outputParameterName) 4 { 5 } 6 7 public override int OnHandle(HttpRequestMessage input) 8 { 9 var stringValue=input.Content.ReadAsString(); 10 return 1; 11 } 12 }

4. Http Classes

WCF Web API provides two classes HttpRequestMessage and HttpResponseMessage for HTTP request and HTTP Response respectively.

5. HTTP Client

HTTP client can be used to connect REST based web services in a fully typed manner. You can use HttpClient to connect to web service, set headers, get fully typed response and work with the data instead of raw parsing. It supports Sync and Async methods to work with the resource.

1 const string address = "http://localhost/odata.web/people/"; 2 var client = new System.Net.Http.HttpClient(address); 3 4 //set which headers do you want 5 client.DefaultRequestHeaders.Accept 6 .Add(new MediaTypeWithQualityHeaderValue("text/json")); 7 8 var personQuery = client.CreateQuery<Person>(); 9 var results = personQuery.ExecuteAsync().ContinueWith(p => 10 { 11 foreach (var result in p.Result) 12 { 13 Console.WriteLine("Person Id:{0} and Name:{1}", result.Id, 14 result.Name); 15 } 16 17 }); 18

6. Queryability

WCF Web API supports OData style querying capabilities. In order to do this all you have to do is to create a method which return IQueryable<T>. Following shows you how simple it is to write a method and expose the method which supports OData style querying capabilities which includes ordering, filtering etc.

Once this is in place you can place request like http://localhost/Person?$filter=Id%20eq%201.It indicates “find me the person with an ID equal to 1”

7. Fluent Configuration

WCF API makes it easy to configure your application. It provides nice fluent style configuration where you can plug containers, handlers, MediaTypeFormatters and your resource classes.

1 protected void Application_Start(object sender, EventArgs e) 2 { 3 IUnityContainer container = new UnityContainer(); 4 container.RegisterType(typeof(PersonResource)); 5 container.RegisterType(typeof(PeopleResource)); 6 container.RegisterType( 7 typeof(IPersonRepository), typeof(PersonRespository), 8 new ContainerControlledLifetimeManager()); 9 10 var config = HttpHostConfiguration.Create() 11 .AddFormatters(new MediaTypeFormatter[] { new JpgFormatter() }) 12 .SetResourceFactory(new UnityFactory(container)) 13 .SetErrorHandler(new CustomErrorHandler()) 14 .AddMessageHandlers(typeof (LoggingChannel)); 15 16 RouteTable.Routes.MapServiceRoute<PersonResource>("person",config); 17 RouteTable.Routes.MapServiceRoute<PeopleResource>("people",config); 18 }

How to get bits.

Either get the bits from the Nuget package or download from http://wcf.codeplex.com.At the time of writing this article (May 2011), WCF Web API is in Preview 4. Although in a CTP stage, Microsoft has made a great start with WCF Web API. It not only allows us to create powerful applications by leverage support of HTTP but also made life of developers very easy by providing minimal effort to achieve this.

References

Glenn Block’s Blog

http://codebetter.com/glennblock/2011/05/15/using-datacontracts-with-wcf-web-api/

Daniel Cazzulino’s Blog

http://blogs.clariusconsulting.net/kzu/

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s