Over the last couple of weeks I have been looking a bit at the WCF Web API which I think is looking very promising. Web API is one of Microsofts newer open source projects, aiming at providing http based services on top of WCF - while providing an easy to use API that give developers full control. In a way this makes me think of MVC, which has given control of the markup back to the developers, just like Web API is trying to do for http. Already loving what MVC has done for me, this makes me very positivt about the approach right off the bat.
RESTful services seem to be all the rage these days, which made me look at some of the choices we have as developers for doing REST. This was really my first look at Web API, so with it being one of the more exciting news at MIX11, it was only natural to take a deeper look.
All journeys begin with a single step – coding it requires a few more
Starting out I build what is close to the hello world version of Web API services for my “business card” site www.dotnetnerd.dk so the data for the site is read from the services. This gave me a nice simple way to get started, and do something that ends up being shown to users. After that I spent an afternoon going more in depth while I was on vacation. Having a newly reinstalled machine with me, I decided to go with Visual Studio Express and IIS Express – both being a positive surprise providing me all I needed for free.
If you are interested in Web API, I recommend doing a new MVC project and installing the WebApi.All and WebApi.CrudHttpSample – this was the very first thing I did, and it illustrates the basics of using WebApi pretty well. So for two minutes of work, you actually get to see how the code works, and you don’t even have to do any typing.
Looking under the covers
Sadly the CrudHttpSample won’t run as it is out of the box. You will need to add a route in the global.asax like so: RouteTable.Routes.MapServiceRoute<MyModelResource>("helloworld");
Now the sample can be run appending “/helloworld/1” to the url, but purposfully it will return a 404 since there are no items in the Dictionary which the sample uses in lieu of a database. Adding a few items in code is pretty trivial though, so to see some data returned this could be the easy way to go.
Once you have a running Web API resource, you can inspect the http communication using Fiddler. As you see data is returned as xml by default. However you can have the resource return json simply by using the Request Builder in Fiddler adding an accept header like: Accept: “application/json”
Trust is good, control is better
What is really nice about Web API is the degree of control. Routes can be set up by adding to the RouteTable, and then adding a WebGet or Webinvoke attribute to specify which verb to handle. The UriTemplate property is then used to define arguments as part of the url and map them to the arguments for the resource method.
[WebInvoke(UriTemplate = "{id}", Method = "POST")]
public Product Post(int id)
The resource methods can also take a HttpRequestMessage<TModel> argument, that gives you access to the content and request headers, so you can be fully http compliant. In the same way you can return a HttpResponseMessage<TModel> object, where you can set the StatusCode and add headers. So doing true http redirects or throwing a 404 NotFound comes very easy.
[WebInvoke(UriTemplate = "", Method = "POST")]
public HttpResponseMessage<Product> Post(HttpRequestMessage<Product> request)
{
var notFoundResponse = new HttpResponseMessage();
notFoundResponse.StatusCode = HttpStatusCode.NotFound;
notFoundResponse.Content = new StringContent("Item not found");
throw new HttpResponseException(notFoundResponse);
}
Formats a..Z
Part of the richfullnes of http is the support for a wide variety of formats. Besides simple dataformats like xml and json that are included in the core Web API framework, it is possible to plug in your own, to support returning anything you want from mediafiles like images or moviefiles to more domain specific formats like vCards.
A format that I tend to run into with customers who like to work with Excel and do imports and exports from misc. applications is CSV. So as a quick test I wrote a very raw CsvFormatter like this:
namespace WebApiDemoApplication.Resources
{
public class CsvFormatter : MediaTypeFormatter
{
public CsvFormatter()
{
SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/csv"));
}
public override void OnWriteToStream(Type type, object value,
Stream stream, HttpContentHeaders contentHeaders, TransportContext context)
{
var result = string.Empty;
var enumerable = value as IEnumerable;
foreach (var item in enumerable)
{
result += string.Join(",", item.GetType().GetProperties()
.Select(p => p.GetGetMethod().Invoke(item, null).ToString()).ToArray()) + "\r\n";
}
var bytes = new UTF8Encoding().GetBytes(result);
stream.Write(bytes, 0, bytes.Length);
}
public override object OnReadFromStream(Type type, Stream stream,
HttpContentHeaders contentHeaders)
{
throw new NotImplementedException();
}
}
}
As you can see formatters support going both ways, but I was too lazy to implement the reading part. Besides writing the formatter it self, we need to plug it in. Configuration turnes out to have a nice fluent API – which just won some easy credit points in my book.
var config = HttpHostConfiguration.Create().AddFormatters(new CsvFormatter());
RouteTable.Routes.MapServiceRoute<Resources.ProductResource>("products", config);
OData my data, wherefore art though OData
On top of all this control and configuration niceness, Web API leverages the OData URL queryformat. All you have to do to make an endpoint queryable is to have it return an IQueryable<TModel>. This will let the consumer of the resource do queries by postfixing the URL like this /products?$skip=2&$top=1
IoC pluggability baked in
During his talk at MIX11 Glenn Block demonstrated how to plugin AutoFac as an IoC container for Web API. First of all I was happy to see that they actually enabled this from day one, because it is something I feel should be trivial, but isn’t always.
At Vertica, we normally use Castle Windsor, but I thought I would try doing the AutoFac sample Glenn showed, so I might learn something. Mostly I liked to see that there were NuGet packages for integrating AutoFac with everything from WebForms to WCF services.
Once again the fluent API provides a nice configuration story.
var cb = new ContainerBuilder();
cb.RegisterType<ProductRepository>()
.As<IProductRepository>();
cb.RegisterType<ProductResource>();
var container = cb.Build();
config.SetResourceFactory(
(t, i, r) => container.Resolve(t), (t, i) => { });
Notice that nothing has to be done to release the instance? This is what I would like for Windsor, who even with transient objects require them to be released. So I kind of like AutoFac already, but in defence of Windsor it has some nice features, that are missing from most other IoC Containers.
To be continued…
So far I think that Web API looks promising and has come off to a good start being at an early stage. In a later blogpost I will be looking at how to use a resource using JQuery and the new JQuery Templates plugin, but I think I have covered enough ground for today – so I will leave you with “all good things come to those who wait”.