Migrating ASP.NET MVC to WebApi with no breaking changes

Recently I’ve had the pleasure to upgrade our REST interface at work from Asp.Net MVC3 to WebApi so I thought a lessons learned or “watch out for this” blog post was suitable, especially since I managed to do it without the need to bump any version number on our server i.e. no breaking changes.

I think there are others out there that have been using the MVC framework as a pure REST interface with no front end, i.e. dropping the V in MVC, before webapi was available.

Filters

First of all webapi is all about registering filters and message handlers and letting requests be filtered through them. A filter can either be registered globally, per controller or per action which imo already is more flexible than MVC.

public class MvcApplication : HttpApplication
{
    protected void Application_Start()
    {
        ...
        GlobalConfiguration.Configuration.MessageHandlers.Add(new OptionsHandler());
        GlobalConfiguration.Configuration.MessageHandlers.Add(new MethodOverrideHandler());
        GlobalConfiguration.Configuration.Formatters.Insert(0, new TypedXmlMediaTypeFormatter ...);
        GlobalConfiguration.Configuration.Formatters.Insert(0, new TypedJsonMediaTypeFormatter ...);
        ...
    }
}

 

Metod override header

Webapi doesn’t accept the X-HTTP-Method-Override header by default, in our installations we often see that the PUT, DELETE and HEAD verbs are blocked. So I wrote the following message handler which I register in Application_Start.

public class MethodOverrideHandler : DelegatingHandler
{
    private const string Header = "X-HTTP-Method-Override";
    private readonly string[] methods = { "DELETE", "HEAD", "PUT" };

    protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        if (request.Method == HttpMethod.Post && request.Headers.Contains(Header))
        {
            var method = request.Headers.GetValues(Header).FirstOrDefault();
            if (method != null && methods.Contains(method, StringComparer.InvariantCultureIgnoreCase))
            {
                request.Method = new HttpMethod(method);
            }
        }

        return base.SendAsync(request, cancellationToken);
    }
}

 

Exception handling filter

In our controllers we throw HttpResponseExceptions when a resource isn’t found or if the request is bad for instance, this is quite neat when you want to short-circuit the request processing pipeline and return a http error status code to the user. The thing that caught me off guard is that when throwing from a controller action the exception filter is not run, but when throwing from a filter the handler is run. After some head scratching I found a discussion thread on codeplex where it’s explained that this is intentional, so do not throw exceptions in your filters.

We have a filter which looks at the clients accept header to determine if our versions (server/client) are compatible, this was previously checked in our base controller but with webapi it felt like an obvious filtering situation and we threw Not Acceptable if we weren’t compatible. This needed to be re-written to just setting the response on the action context and not calling on the base classes OnActionExecuting which imo isn’t as clean design.

public class VersioningFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext actionContext)
    {            
        var acceptHeaderContents = ...;
        if (string.IsNullOrWhiteSpace(acceptHeaderContents))
        {                
            actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.NotAcceptable, "No accept header provided");
        }
        else if (!IsCompatibleRequestVersion(acceptHeaderContents))
        {             
            actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.NotAcceptable, "Incompatible client version");
        }
        else
        {
            base.OnActionExecuting(actionContext);
        }
    }
}

 

Request body model binding and query params

In MVC the default model binder mapped x-www-form-encoded parameters to parameters on the action if the name and type matched, this is not the case with webapi. Prepare yourself to create classes and mark the parameters on your controller with the FromBody attribute even if you only want to pass in a simple integer that is not a part of the URI. Furthermore to get hold of the query params provided in the URL you’ll need to pass in the request URI to the static helper method ParseQueryString on the HttpUtility class. It’s exhausting but it will work and it still doesn’t break any existing implementation.

[HttpGet]
public HttpResponseMessage Foo([FromBody]MyModel bar)
{
    var queryParams = HttpUtility.ParseQueryString(Request.RequestUri.Query);
    string q = queryParams["q"];
    ...
}

 

Posting Files

There are plenty of examples out there on how to post a file with MVC or WebApi so I’m not going to cover that. The main difference here is that the MultipartFormDataStreamProvider needs a root path on the server that specifies where to save the file. We didn’t need to do this in MVC, we could simply get the filename from the HttpPostedFiledBase class. I haven’t found a way to just keep the file in-memory until the controller is done. I ended up with a couple of more lines of code where I create the attachments directory if it doesn’t exist, save the file and then delete it once we’ve sent the byte data to our services.

[ActionName("Index"), HttpPost]
public async Task<HttpResponseMessage> CreateAttachment(...)
{
    if (!Request.Content.IsMimeMultipartContent())
    {
        throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
    } 

    string attachmentsDirectoryPath = HttpContext.Current.Server.MapPath("~/SomeDir/");
    if (!Directory.Exists(attachmentsDirectoryPath))
    {
        Directory.CreateDirectory(attachmentsDirectoryPath);
    }

    var provider = new MultipartFormDataStreamProvider(attachmentsDirectoryPath);
    var result = await Request.Content.ReadAsMultipartAsync(provider);
    if (result.FileData.Count < 1)
    {
        throw new HttpResponseException(HttpStatusCode.BadRequest);
    }
    
    var fileData = result.FileData.First();
    string filename = fileData.Headers.ContentDisposition.FileName;
    
    Do stuff ...

    File.Delete(fileData.LocalFileName);    
    return Request.CreateResponse(HttpStatusCode.Created, ...);
}

 

Beaking change in serialization/deserialization JavaScriptSerializer -> Newtonsoft.Json

So WebApi is shipped with the Newtonsoft.Json serializer, there are probably more differences than I noticed but date time types are serialized differently with Newtonsoft. To be sure that we didn’t break any existing implementations I implemented my own formatter which wrapped the JavaScriptSerializer and inserted it first in my formatters configuration. It is really easy to implement custom formatters, all you need to do is inherit MediaTypeFormatter.

public class TypedJsonMediaTypeFormatter : MediaTypeFormatter
{        
    private static readonly JavaScriptSerializer Serializer = new JavaScriptSerializer();
    
    public TypedJsonMediaTypeFormatter(MediaTypeHeaderValue mediaType)
    {        
        SupportedMediaTypes.Clear();
        SupportedMediaTypes.Add(mediaType);
    }

    ...

    public override Task<object> ReadFromStreamAsync(Type type, Stream readStream, System.Net.Http.HttpContent content, IFormatterLogger formatterLogger)
    {
        var task = Task<object>.Factory.StartNew(() =>
        {
            var sr = new StreamReader(readStream);
            var jreader = new JsonTextReader(sr);
            object val = Serializer.Deserialize(jreader.Value.ToString(), type);
            return val;
        });

        return task;
    }

    public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, System.Net.Http.HttpContent content, System.Net.TransportContext transportContext)
    {
        var task = Task.Factory.StartNew(() =>
        {
            string json = Serializer.Serialize(value);
            byte[] buf = System.Text.Encoding.Default.GetBytes(json);
            writeStream.Write(buf, 0, buf.Length);
            writeStream.Flush();
        });

        return task;
    }
}

 

MediaFormatters Content-Type header

Any real world REST interface needs to have a custom content type format and by default the xml and json formatter always returns application/xml respectively appliation/json. This is not good enough, I suggest that you create custom implementations of JsonMediaTypeFormatter and XmlMediaTypeFormatter and insert them first in your formatters configuration. In your custom formatter just add your media type that includes the vendor and version to the SupportedMediaTypes collection. In our case we also append the server minor version to content type as a parameter, the easiest way to do that is by overriding the SetDefaultContentHeaders method and append whichever parameter you want to the header content-type header.

public class TypedXmlMediaTypeFormatter : XmlMediaTypeFormatter
{
    private readonly int minorApiVersion;

    public TypedXmlMediaTypeFormatter(MediaTypeHeaderValue mediaType, int minorApiVersion)
    {
        this.minorApiVersion = minorApiVersion;
        SupportedMediaTypes.Clear();
        SupportedMediaTypes.Add(mediaType);
    }

    ...

    public override void SetDefaultContentHeaders(Type type, HttpContentHeaders headers, MediaTypeHeaderValue mediaType)
    {
        base.SetDefaultContentHeaders(type, headers, mediaType);
        headers.ContentType.Parameters.Add(new NameValueHeaderValue("minor", minorApiVersion.ToString(CultureInfo.InvariantCulture)));
    }
}

 

I think that covers it all, good luck migrating your REST api!

I might cover upgrading from WIF 3.5 (Microsoft.IdentityModel) to WIF 4.5 in my next post, or thinktectures startersts to identity server v2. Take a wild guess what I’ve been busy with at work! ;-)

WinRT app @ Labdays

Installed win8 on my work laptop not too long ago so I decided to create my first winrt app during lab days at work. Due to lack of imagination I created a simple dashboard app for our product SAFE (really ugly page on saabgroup btw).

Started of by looking at some sessions on channel9 and googled design patterns, frameworks and ended up with the following:

I ended up writing a custom navigation service that I bootstrapped on application startup to make the IOC container from MVVM Light play nicely together with the AlternativeFrame from WinRT Xaml Toolkit. If you pay attention to the navigation between pages you can notice the nice dissolve transition which is done in AppShell.xaml in only 4 lines of markup.
Once I got the basic architecture in place I noticed that the panorama control from windows phone was missing for winrt. One google search later I found a blog post that addressed this issue so I ended up copying some code since I didn’t want to install the entire nuget package win8nl. What it basically does is to add a panorama behvior to the FlipView control. The sad thing though is that you can’t flick the screen if you don’t have a touch screen, which is extremely frustrating!
As for what goes for component arts data viz library I really think it’s not worth to pay for (trial is free), in the short time I played around with it I stumbled upon several bugs. An ugly work around for the PieChart control can be seen in the code behind file MainPage.xaml.cs. When data binding to an observable collection the control goes bananas as items are added to the collection, I needed to reset the DataSource for each added item for it to work properly.
All and all I’m pretty satisfied with the choice to use MVVM Light together with WinRT Xaml toolkit and the custom navigation service, I will definitely reuse that part for other projects.
Anyways the result can be seen in the vid below, you can get the source code here, if you’re interested in how I hooked up the components and architecture. You will probably not be able to run the application since it requires our back-end and I didn’t spend too much time on exception handling.

 

Merry x-mas everybody and a happy new year, I’m off for two whole weeks!

 

What about WCF 4.5 and the async/await pattern?

From what I’ve heard it should be pretty smooth to produce asynchronous server/client code with .net 4.5, so let’s try it out! Defining async methods on the service contract is now a lot cleaner :

[ServiceContract]
public interface IPeopleService
{
	[OperationContract]
	Task<IList<Person>> GetPeople();
}

instead of the wcf 4.0 way which would look something like this :

[ServiceContract]
public interface IPeopleService
{
	[OperationContract(AsyncPattern=true)]
	IAsyncResult BeginGetPeople(AsyncCallback cb, object state);

	[OperationContract]
	IList<Person> GetPeople();

	[OperationContract]
	IList<Person> EndGetPeople(IAsyncResult ar);
}

the server side implementation of the operation when returning a task is straightforward :

public async Task<IList<Person>> GetPeople()
{
	Task t1 = Task.Delay(500);
	Task t2 = Task.Delay(500);
	await Task.WhenAll(t1, t2);

	return await Task.Factory.StartNew(() => people);
}

If you don’t want to await something in the method you can skip the async keyword and still return a Task as shown below, async on a method simply tells the compiler that “I’m going to await something in this method”.

public Task<IList<Person>> GetPeople()
{
	return Task.FromResult(people);
}

Anyways it’s really nice to skip the non-implemented begin/end methods on the server which was simply boiler plating in .net 4.0. For the sake of simplicity the service will be hosted in a console application and for consuming the service I’ve implemented a simple proxy that inherits ClientBase<TChannel> and implements the contract. See the code if this confuses you (which probably means that you’re a noob ;-)). The client code when working with tasks is clean and straightforward as well :

var serviceProxy = new PeopleServiceProxy("PeopleServiceEndpoint");

Task<IList<Person>> people = serviceProxy.GetPeople();
people.ContinueWith(
	x =>
		{
			foreach (Person person in x.Result)
			{
				Console.WriteLine(
					"{0} {1} born {2}",
					person.FirstName,
					person.LastName,
					person.BirthDate.ToShortDateString());
			}
		});

We can control on which thread we will continue by passing in a TaskScheduler. So far so good, so what about testing? I’m using Nunit which integrates really well with VS when using resharper. I want to write an integration test (not unit) to make sure everything works well including the WCF part since unit testing my simple service is too easy ;-) I’ll host the service in the Setup method and take it down in the teardown. A simple test then looks like :

[Test]
public void ShallBeAbleToGetDateTimeFromService()
{
	IPeopleService serviceProxy = new PeopleServiceProxy("PeopleServiceEndpoint");

	Task<IList<Person>> getPeopleTask = serviceProxy.GetPeople();
	getPeopleTask.Wait();

	IList<Person> result = getPeopleTask.Result;

	Assert.IsNotNull(result);
	Assert.AreEqual(2, result.Count);

	(serviceProxy as IDisposable).Dispose();
}

Obviously we’d use facades to call on services in a real application but the principle is the same. It doesn’t get much cleaner than this imo.

/A

Get the code here! (67KB)