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.



thanks



k

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 127.0.0.1.  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!

Kris

Thursday, 16 August 2012

System.Web.HttpException (0x80004005): Failed to load viewstate

Call stack:-

at System.Web.UI.Control.LoadViewStateRecursive(Object savedState)
at System.Web.UI.Control.LoadChildViewStateByIndex(ArrayList childState)
at System.Web.UI.Control.LoadViewStateRecursive(Object savedState)
at System.Web.UI.Control.LoadChildViewStateByIndex(ArrayList childState)
at System.Web.UI.Control.LoadViewStateRecursive(Object savedState)
at System.Web.UI.Control.LoadChildViewStateByIndex(ArrayList childState)
at System.Web.UI.Control.LoadViewStateRecursive(Object savedState)
at System.Web.UI.Control.LoadChildViewStateByIndex(ArrayList childState)
at System.Web.UI.Control.LoadViewStateRecursive(Object savedState)
at System.Web.UI.Control.LoadChildViewStateByIndex(ArrayList childState)
at System.Web.UI.Control.LoadViewStateRecursive(Object savedState)
at System.Web.UI.Control.LoadChildViewStateByIndex(ArrayList childState)
at System.Web.UI.Control.LoadViewStateRecursive(Object savedState)
at System.Web.UI.Control.LoadChildViewStateByIndex(ArrayList childState)
at System.Web.UI.Control.LoadViewStateRecursive(Object savedState)
at System.Web.UI.Page.LoadAllState()
at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)

I have had a .NET 1.1 webform operating on a website since 2004 and it should be backward compatible with .NET 4.5 (RTM), and largely, it is! However, I have found that if you use ASP.NET Bundling it will screw up the viewstate and you’ll end up with the error above.  I found this out by decoding the viewstate and noticing it contained data from the Bundling URLs and I thought to myself “Why does bundling care about ViewState?”.  At the moment, I have no solution, however, I’ll post back here if I find one.

You can prove that it’s Bundling that causes the issue by simply removing the call to: System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl from your page

thanks

Wednesday, 4 July 2012

IIS7 No response; In Fiddler2: "readresponse() failed for POST requests to a host IP which is not local. In Failed Request Tracing error in ManagedPipelineHandler with “The I/O operation has been aborted because of either a thread exit or an application request. (0x800703e3)”

 

Just spent 10 hours trying to figure out why a WorldPay callback to my development machine was not working.

This was simply because I had “Email scanning” protection enabled in AVG Antivirus.  If you turn this OFF, everything will work fine.

This is related to the Stack Overflow post: http://stackoverflow.com/questions/7439063/iis-asp-net-website-managedpipelinehandler-error-an-operation-was-attempted

Saturday, 5 May 2012

Encountering “System.IO.FileLoadException: Mixed mode assembly is built against version 'v2.0.50727' of the runtime and cannot be loaded in the 4.0 runtime without additional configuration information.” inside a Test Project in Visual Studio 11 beta?

Even though you may have configured the app.config file of the Test Project with the following configuration, it’ll make no difference when trying to use .NET 2.0 assemblies from a .NET 4 Test project.

<startup useLegacyV2RuntimeActivationPolicy="true">
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>

This configuration node is not effective because Test projects are DLLs not executables. This node will not effect the actual underlying executable which hosts the Test Project’s DLL when you run tests.  You need to change the config of the executable which for me is hosted under: C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\CommonExtensions\Microsoft\TestWindow.

Look for “vstest.executionengine.x86.exe”.  This is the executable which VS runs while unit testing. Now find “vstest.executionengine.x86.exe.config”

Add the above configuration node to this file, save it, run your tests and now you should find the above exception disappears. 

The actual exception for me occurred while loading a Windows Azure SDK DLL:

Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment.InitializeEnvironment()
   at Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment..cctor()
   --- End of inner exception stack trace ---
   at Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment.get_IsAvailable()

Hopefully Microsoft will fix this issue in time for RTM.