Tuesday, 27 November 2012

IIS / httpErrors / ASP.NET Web API / Fully embracing HTTP in Web API and having a professional web application is mutually exclusive.

Hi there, I’m going to get to the point really quickly because I’m very busy. 

With ASP.NET Web API introduced in .NET 4.5 we’re encouraged to embrace HTTP as a protocol fully with RESTful APIs, or indeed more RPC-esque APIs.  When we don’t find a record inside the database we can do this:

   1: Request.CreateErrorResponse(HttpStatusCode.NotFound, "The record was not found");

Aint that beautiful?  If you don’t appreciate it; well you should because now, an error response is returned to the client in a data format that the client/browser requests.  So if you’re interacting with the API via JSON then you’ll get back a JSON formatted response. Same with XML etc.

The idea is we utilise HTTP response codes (200, 404 etc) to represent a plethora  of different types of response. Before we might just return error codes embedded inside the response and the HTTP response status would probably be 200 (OK).

Hold all that in your short term memory for a sec.

With IIS7+ we’re encouraged to embrace the new httpErrors section inside web.config. With this it means you can return friendly error messages to the client/browser.

   1: <httpErrors defaultResponseMode="File" errorMode="DetailedLocalOnly" existingResponse="Replace" xdt:Transform="Insert">

   2:   <clear />

   3:   <error path="html\system_error.html" responseMode="File" statusCode="400" />

That’s great.  Now you don’t have IIS specific error messages going to the client / browser.  Not only does this mean your web app can fail slightly more gracefully and helpfully (to the user), but also, it’s vastly more professional looking.


Above I have described two great features of the MS web stack.  Unfortunately, they are mutually exclusive.  You cannot host Web API inside the same project as a web app and have these two items function.  IIS will hijack your Web API responses because of the attribute on the httpErrors node existingResponse=replace.  If you get rid of this attribute and use PassThrough, then your Web API responses will get through OK.  However, now if you have an error in the website outside of the scope of the web api, then the client will see non-custom error messages (might be detailed or not, depending on the errorMode).

So I have reverted back to returning status HTTP 200 for all Web API business exceptions.  In reality, the the API client is not looking at the HTTP status code anyway, it’s looking at the returned content-type (if it’s the expected content-type, e.g. JSON), then it’ll look inside the JSON envelope (see JSend / AmplifyJS) and figure out was the real API response was.  If the content-type was not expected, then the API client will assume something worse happened.  It’ll examine the HTTP status code and I actually have error codes inside the custom IIS error pages, so that the API client can do a simple string search inside the html content to see what the overall problem was.  But hey, that’s very much application-specific stuff.  Each app will do it differently.

However, in any case, it does appear that custom error messages AND formatted Web API error responses are mutually exclusive for the time being.  If anyone knows how to do both without having to split the project into an API project and the web project with the their own separate configurations, feel free to comment.



Wednesday, 21 November 2012

Accessing the Windows Azure Compute Emulator from Hyper-V, Virtual PC or the external network

Unlike IIS, the Windows Azure Compute Emulator does not listen for external requests on your network IP.  It only listens on the local loopback address  As I have found out, this is a big pain for cross browser testing because you cannot install Internet Explorer 7, 8, 9 and 10 side-by-side, so you have to either use external PCs with old browsers or create virtual machines in Oracle VirtualBox or Hyper-V with those browsers installed.

To solve this problem, you could:

  • Use AnalogX PortMapper – however, you need to remember to shut it down before the emulator starts and then start it again after it’s started… this is too much friction!
  • Create a separate IIS website listening on a different port to 80, add that as a Firewall exception and access the application externally that way – however, the drawback is that you may need to change your application architecture to run under the two different contexts.  Also #1, you have the memory overheads of having 1 + N instances of the app in memory. Also #2, you’re not testing the app in emulated conditions when using IIS – which means it’s not really a thorough test.  Also #3, it’s more friction.
  • You might find there’s a way to configure Hyper-V to use the host network connection and loopback adapter… I’m not a Hyper-V expert, but I tried and failed. Probably not possible!?

However, the best solution was totally frictionless: Just use PJS PassPort: http://sourceforge.net/projects/pjs-passport as detailed in this other blog post: http://blog.sacaluta.com/2012/03/windows-azure-dev-fabric-access-it.html 

Hope this helps someone!  I have posted this as an answer on stackoverflow as well; hopefully this will work for everyone now!