ASP.NET Web API is released! What's new in Web API and how to use it!

Strath

August 15th, 2012

ASP.NET Web API is released! What’s new in Web API RTM and how to use it!

And why is it good for you

If you have been following this blog for a while now (and if not, I really hope you will!), you’d know that I am a big fan of Web API. I have been blogging a lot about Web API, through its beta, RC stages and even about features that were only available through the Codeplex builds and I have to say that it is a terrific bridge between CLR and HTTP and fits really nicely into the existing landspace of web technologies.

With that said, today is a really big and important day, as Web API has been publicly released in its RTM version. This effectively means that you have binaries you can safely use in production scenarios and take advantage of all the great features of the framework. You can download MVC4 (including Web API) RTM here.

Let’s go through the new features in RTM.

Per-route message handlers

Per-route handlers provide you very nice granular control over the framework’s setup within the context of different (surprisingly) routes of your application. This feature was the most popular one at Codeplex Web API issues repository and is surely going to be welcomed by the community with open arms.

Consider a simple scenario – you have a free section of your API and parts of the API which are protected by an API key.

This simple key-checker just checks if API key in querystring is not empty. Of course this is a dummy implementation, but it’s just for demo purposes. Now you might want to plug this into a specific route only. In order to use this on a per-route basis, you’d normally need to also set InnerHandler to the default HttpControllerDispatcher so that it continues to participate in the pipeline.

In this case, you have a free route now: “/api/free/” and a regular paid route: “/api/[controller]/” which you have to access through an API key.

Per-controller configuration

This is arguably the biggest change as it will save tons of time and help in a lot of scenarios. You are no longer tied to the GlobalConfiguration, but can provide your own configuration for a specific controller.

This is achieved through the use of IControllerConfiguration interface, which can be found here.

What this allows you to do is for example have you own dependency resolution rules on a specific controller, or your own content negotiation or formatting on a specific controller. Similarly to per-route handlers, the possibilites here are very broad and the flexibility this brings is tremendous.

Mike Stall wrote a nice blog post a while ago, showing how you can wire up the per controller configuration using a simple configuration attribute, so I really recommend you check it out.

Changes to content negotiation to allow more flexibility

I blogged about that in my content negotiation post, but you can now very easily force your Web API to return 406 error if no media type match is found. By default, if none of the main 3 conneg conditions are met (please be referred to the above conneg post to find out more about these), Web API would return a response in the format in which the Type can be serialized, which is often not desireable.

To do this, just pass excludeMatchOnTypeOnly to the constructor of the DefaultContentNegotiator to true.

Additionally, you can now override a whole bunch of the default content negotiators methods (in RC the only one expose was the generic “Negotiate()”):
protected virtual Collection of Mediatypeformattermatch ComputeFormatterMatches(Type type, HttpRequestMessage request, IEnumerable<Mediatypeformatter> formatters), used to gather all formatters matches

protected virtual MediaTypeFormatterMatch SelectResponseMediaTypeFormatter(ICollection<Mediatypeformattermatch> matches), used to select the best formatter match

protected virtual MediaTypeFormatterMatch MatchMediaTypeMapping(HttpRequestMessage request, MediaTypeFormatter formatter) used to determine match for MediaTypeMappings

protected virtual MediaTypeFormatterMatch MatchAcceptHeader(IEnumerable sortedAcceptValues, MediaTypeFormatter formatter), used to determine match basedrequest’s accept headers

protected virtual MediaTypeFormatterMatch MatchRequestMediaType(HttpRequestMessage request, MediaTypeFormatter formatter), used to determine match by inspecting the content type of the request

protected virtual MediaTypeFormatterMatch MatchType(Type type, MediaTypeFormatter formatter), used to determine if the formatter can even write the selected Type

protected virtual IEnumerable SortMediaTypeWithQualityHeaderValuesByQFactor(ICollection headerValues), used to sort charset, language and related headers by quality

protected virtual IEnumerable SortStringWithQualityHeaderValuesByQFactor(ICollection headerValues), used to sort accept charset

protected virtual Encoding SelectResponseCharacterEncoding(HttpRequestMessage request, MediaTypeFormatter formatter), used to determine encoding

This allows you to have granular control over how conneg is performed in your application. Again, if you wish to dig deeper, please have a look at this commit at Codeplex.

One other content negotiation related change is the removal of MediaRangeMapping with this commit – so if you are using it anywhere in your RC-driven code, you are unfrotunately out of luck. But since, it wasn’t working properly in the first place, chance are no one is using it anyway :)

Introduction of ProgressMessageHandler

Web API RTM introduces a special type of DelgatingHandler, called ProgressMessageHandler. As the name suggests, it can be used to track the progress of both the send operation and the download operation invoked on your Web API endpoint.

I have already mentioned this feature in a blog post few weeks ago. I recommend you revisit that post, but here is the gist of the progress handler – here in conjunction with WPF UI

The ability to track upload and download progress just like that, is a wonderful addition to the ASP.NET Web API (or rather to the System.Net.Http, since as you can see here you can use it outside Web API as well). It exposes all kinds of useful information for up- and download of data when communicating with the HTTP endpoint.

In our case, we leverage on HttpProgressEventArgs.ProgressPercentage which can be directly assigned to WPF’s ProgressBar and utilized to visually track upload progress.

Multipart stream changes (yes, for the better)

A while ago I blogged about a file uploader for Web API. It worked nicely, but was quite limited in terms of handling the uploaded files. For example, the files were arbitrairly getting saved you having any chance to manipulate the uploaded stream in memory – if you wanted to for example rename the files, you had to work around that by using System.IO API after the upload.

The reason for this is that the default MultipartStreamProvider only exposed the raw IEnumerable<HttpContent> collection and didn’t allow any post processing of the uploaded data.

Now, it’s much simpler, and Henrik has a great post explaining all the changes in deail. I will update the mentioned upload demo as well later on.

The change itself can be reviewed through this commit.

Introduction of PushStreamContent

PushstreamContent is a nice and sexy feature that, as the name suggests, allows you to push a stream of data to the client over HTTP. If you are a regular reader of this blog (and I hope you are!), you probably recall that I wrote about that before, showing a simple chat built using Javascript SSE (server sent events) and PushstreamContent – the kicker there was that in order to use the functionality you needed the latest Web API source from Nuget or Codeplex – now you just need Web API RTM.

Example:

Quick and easy error response creation

We actually already touched based on that in one of the previous examples. If you read my tutorial on message handlers a few months ago, I was using a custom helper to create an error response. Now it’s much simpler, and if you look back to our API key example from this article:

You can see how easily you can break the flow of code at any point and throw an HTTP response exception, by passing in a resposne code and some information.

Message handlers processing reversal

This is a subtle yet important change, and if you do not cater for it, you might see unexpected results in your application.

The change was commited and is nicely explained here by Henrik, and the gist of it is that the processing of message handlers in the request-response pipeline used to be bottom-up and now is reversed to top-down.

In other words, the “russian doll” model remains, it’s just been flipped upside down.

MediaTypeFormatter (breaking) changes

The “read” signature of the base MediaTypeFormatter has been changed from

to

This exposes the entire HttpContent to the formatter, rather than just its headers, providing even greater deal of information to it. I mentioned this change last month in a media type formatter post. What you’d need to do, if you have any custom formatter is to cater to this change, as the old version of the code won’t compile any more.

Reading form data

If you don’t want to or don’t need to rely on Web API paramtere pinding, it is now possible (through this commit) to read the data from the request body or from the querystring directly into NameValueCollection.

This is the new HttpContent extension method for reading into nv:

It is also possible to read directly into JObject, using the regular ReadAsAsync<T> extension, where T would be JObject.

Simple paramteres are now bound [FromUri] bydefault

There has been a lot of consuion in the community about binidng simple parameters. Mike Stall posted a fantastic, in-depth explanation, of the paramater binding Web API style (because it is much different than what MVC does, to which people are used to).

One of the question most often asked is why my quersyting string/int/simple paramater is null. Well, usually the reason was your method was missing [FromUri].

Now it’s been changed and the default is [FromUri] so you don’t need any decorators to make this behavior work. On the contrary, if you create the default Web API project with RTM you’d see the explicit [FromBody] attributes instead – because that’s what needed to fish them out of the body now.

Few other minor changes

I think I covered all the major things – there are several other minor changes. These include changes to UrlHelper, HttpClientFactory or IHostBufferPolicySelector.

Summary

I hope you will have fun with Web API RTM. If you were reluctant to put RC version “out there” on the wbe, this release now can now go safely to production and fuel your great new applications.

And you can be sure that I will continue to blog about Web API!

Be Sociable, Share!

  • http://www.tradepoint360.com James Hancock

    Excellent post!

    Looks like a Delete method with ienumerable as the parameter is broken in the release version.

    Before you could do this which is correct against the RFC for HTTP:

    http://localhost/api/tasks/delete?ID=XXX&ID=YYY

    And then have a method signature as a delete method and IEnumerable ID like this;

    public void Delete(IEnumerable<int) ID) …

    And it would allow you to delete multiples. Obviously in any real world scenario this is highly important to save bandwidth on multiple requests. Further it's standards compliant too.

    So is this a bug that should be fixed? Is there a work around?

    What I was actually trying to accomplish is figuring out how to remap a single ID value to the IEnumerable Delete method signature instead of getting a not found so that it would just be an IEnumerable with a single item so that I didn’t have to have two methods….

    Thanks!

    • Filip W

      I haven’t tried that with Delete, but there is no reason why this shouldn’t work.

      Have your tried putting [FromUri] on the Delete action?
      public void Delete([FromUri] IEnumerable<int>) ID)
      and then you should be able to do:
      http://localhost/api/tasks/delete?ID=XXX&ID=YYY

  • http://www.tradepoint360.com James Hancock

    Also, is there any ETA on getting OData querying support back in? This is a serious omission that breaks code built on the RC and Beta and is virtually required for any serious development in large projects….

    Thanks!

    • Filip W

      James, OData is already “back” – I actually forgot to mention that :) It’s available as a separate package, Microsoft.AspNet.WebApi.OData on Nuget in a preview/alpha form. Full release is coming later this fall. You can grab it from here (although I believe it’s still broken, it had dependency issues, but should still be fixed today). There is a nice overview post available here.

  • Pingback: The Morning Brew - Chris Alcock » The Morning Brew #1170

  • Pingback: Dew Drop – August 17, 2012 (#1,384) | Alvin Ashcraft's Morning Dew

  • számlázó

    “It’s available as a separate package, Microsoft.AspNet.WebApi.OData on Nuget in a preview/alpha form”

    wov wov wov

    so in this case I’ll start reading this post again.:)

  • Pingback: BitterCoder – Final Thoughts

  • Andrew Webb

    Ooh… thanks for the heads-up about the message handlers order-of-execution reversal. That change had slipped me by. I must read all of your Web API posts…

  • Pingback: Web API Implementation – Final Thoughts | Catch Blogs