Deprecating Resources Over MVC

September 16, 2012 01:14 by Admin

ASP.Net MVC 4 has been released and it comes with the Web API, a new framework to support HTTP based services. This is what I have been waiting for… a product from Microsoft that means my Resources Over MVC (ROM) project can be deprecated… or can it?

So what features from ROM can the Web API support and which can’t it support (at least out of the box)? Let’s look at the features supported by ROM (although more features have been added since, the majority were listed in a post written as MVC 2.0 came out).

Multiple Formats

Allowing the same resource to be represented in a number of formats is important if you want to enable the widest range of client technologies to use your web service. Way back in my third post I first discussed supporting more than one representation. I started with XML, JSON and XHTML then in the fourth post I introduced one more representation, HELP, which would return XHTML with extra documentation and a test harness.

XML Serialization

The Web API comes out of the box with JSON and XML support. There is one catch though, the released version defaults to using the Data Contract XML Serializer for XML serialization rather than the much more powerful XmlSerializer. Oddly it does default to using the more powerful JSON.Net for serializing JSON rather than the Data Contract JSON Serializer. I think it odd as the XmlSerializer and JSON.Net both support a very similar set of attributes and naming conventions to allow precise control of the serialization process. For example they both support the incredibly useful (but little known) propertyNameSpecified pattern for setting whether a value should be serialized and indicating whether it has been de-serialized. Luckily, you can switch to using the XmlSerializer by putting the following call in your start up code (e.g. in WebApiConfig):

 

   GlobalConfiguration.Configuration.Formatters.XmlFormatter.UseXmlSerializer = true;

 

There is still one slight down side… the Web API team have not cleaned up the XML that is generated by the XmlSerializer. It will output extra default namespaces resulting in XML such as this being created:

 

   <MyObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:xsd="http://www.w3.org/2001/XMLSchema" />

 

If you don’t like these “ambient” namespaces, perhaps you could vote up my suggestion on the user voice site to allow us to remove them.

HTML Serialization

Out of the box the Web API does not have a HTML formatter. In ROM we make use of the standard MVC view handling to provide a powerful way to support HTML representations. Examples have been written that show how the Razor engine could be hosted to provide a HTML view. However, this hosting mechanism would need to be quite sophisticated if it was to support resolving views and partials as per ASP.Net MVC. This has also been raised on the user voice site.

I am considering using a different approach, generating the HTML dynamically in much the same way that JSON.Net and the XmlSerializer work… in other words create an HtmlSerializer that outputs HTML in a consistent manner. This would remove all need for hand written views… more on this in a future post!

Help Format

ROM supports an easy way to provide help / documentation in-line with the API. The content of the help is not auto-generated. The Web API provides an interface (IApiExplorer) that can be used to investigate the resources that are exposed by the API. Yao has described a downloadable preview of how this interface might be used in the future to automatically generate help pages. I think this will be a powerful feature and a good start has been made. I would like to see it “in-line” with the API (i.e. responding to the same URIs)… but this could save a lot of documentation effort.

Overloading POST

As discussed in parts 8 and 9 of my series, there are some user agents that cannot use all the HTTP Verbs we might want to support. For example PUT and DELETE are generally not supported by browsers and when using HTTP Basic Authentication, Flash only allows POST.

One technique often used to circumvent these restrictions is to use a POST, but indicate the actual verb the client wants to use in some other way. This is often called “Overloading POST”. By part 19, ROM supported the following options

  • Add the verb to a request header. By default the web service will check the X-Http-Method-Override header. So the following would cause the web service to perform a delete: ◦X-Http-Method-Override: DELETE
  • If the request is a FORM post (i.e. it contains key / value pairs used when submitting a form) the web service looks for a FORM variable called X-Http-Method-Override. The value is then used as the verb
  • The web service also looks for a variable called X-Http-Method-Override in the query string.

Out of the box, the Web API does not support Overloading of POST, but it is fairly trivial to implement by deriving a class from DelegatingHandler. In a future post I’ll provide an implementation that provides the same functionality supported by ROM.

Accept Header

A well behaved HTTP server should inspect the Accept header to decide what format to use when returning a resource representation. The Web API does inspect the Accept header.

Often, for simple user agents, it is necessary to provide other methods for them to dictate the format they want returned. For example, adding format=xml to the querystring. ROM added full support for this back in post 19. The Web API supports this too. The following added to the application start up (e.g. in the WebApiConfig class) would add the same support:

   GlobalConfiguration.Configuration.Formatters.XmlFormatter.MediaTypeMappings.Add(
      new QueryStringMapping("format", "xml", "application/xml"));

The one small gripe I have with the Web API’s implementation is what it does when the Accept header supplied by the User Agent does not dictate an order of preference for the formats. If more than one of the formats is supported the Web API simply asks each MediaTypeFormatter in turn if it supports one of the acceptable types, and the first one that says yes wins. Ideally I would like to infer an implicit preference for types that have the same quality factor from the order they appear in the header. It is only a small gripe because it appears in the first pass through the formatters, it ignores a */* format. So whereas when a server that supports both XML and JSON receives an Accept header of:

   Accept: application/xml, application/json

it might result JSON or XML depending on the order that the formatters were configured server side, a header of:

   Accept: application/xml, */*

Will return XML rather than JSON (which in theory could have been returned if the server wanted as */* means the user agent is prepared to accept anything). So in most real world solutions, the Web API will return an appropriate format.

Accept-Charset

Another header supported by ROM is the Accept-Charset header that allows the user agent to dictate the character encoding it wants (e.g. utf-16, utf-8 etc.). The Web API supports this header pretty well. There is a known issue that means if the user agent requests an encoding it doesn’t understand, rather than returning an HTTP 406 Not Acceptable error, it returns a utf-8 representation. Hopefully this minor issue will be fixed soon.

Content-Type Header

The new Web API supports this header… no problems here!

Allow Header

The Allow header (as defined by RFC-2616) can be used by the web service to indicate which HTTP Verbs are valid against a particular resource. ROM supports this. Currently the Web API does not support it, but it is up on the user voice site for consideration, where you can vote for it to be implemented.

Areas

ROM sits on top of ASP.Net MVC and as such it benefits from Area support. The Web API does not support areas which can lead to errors such as:

Multiple types were found that match the controller named ‘xyz’. This can happen if the route that services this request (‘api/{controller}/{id}’) found multiple controllers defined with the same name but differing namespaces, which is not supported.

The request for ‘xyz’ has found the following matching controllers: MvcApplication.Areas.Abc.Controllers.Api.XyzsController MvcApplication.Controllers.Api.XyzsController

There are some work-arounds suggested out there, but for now there is nothing in the box. It is a shame this isn’t supported yet, but I’m sure they will address it soon enough… again it is mentioned of the user voice site.

Conclusion

I’m pretty impressed with the ASP.Net MVC 4 Web API… it has been a long time coming. I started work on ROM (originally it was just an example shared on this blog) back in September 2008. I always hoped Microsoft would eventually produce something “in the box”. Four years on, after a few glimpses and false starts, they have. It still needs a few additions before I could use it in place of ROM:

  • A HTML Serializer – I’m going to see what I can do about this
  • Support for Help – They are starting on this functionality and hopefully will get there
  • Overloading POST – Hopefully I can implement this

The good news is, for at least two of these, the extensibility points should allow me to fix them. There are a few “nice to haves” I hope will be fixed (in descending priority):

  • Cleaned up XML serialization
  • Support for “Areas”
  • Support for the Allow header
  • Implicit ordering when handling the Accept header

So lets see if I can fix two or three things in my top list, then I’ll be ready to recommend the deprecation of ROM!


Add comment

  Country flag

biuquote
  • Comment
  • Preview
Loading