Handling .ASMX Soap Faults in Silverlight 3
Silverlight 3.0 has much better support for soap faults than Silverlight 2. But it’s still not perfect.
The majority of the time it works well with WCF services with some tweaks, as this MSDN article explains.
But what about old .ASMX .NET webservices?
There’s a couple things to understand before we handle those soap faults.
First, by limitations on the browser stack that I won’t go into detail, Silverlight can’t handle HTTP 500 responses. So our first task is to make sure that any ASMX responses are HTTP 200.
Second, ASMX faults are not as nice as WCF faults. So we have to handle them a little bit differently once we get them in Silverlight.
Let’s get started on the first task.
The easiest way of making sure all .ASMX responses are sent out of your server as HTTP 200 is to create a IHttpHandler.
To create your IHttpHandler, simply create a standard .NET Class Library, reference System.Web and add a regular class with this code in it:
public class SilverlightSoapFaultHandler : IHttpHandler
{
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
//
// ScriptHandlerFactory and friends are sealed so have to use reflection..
//
// Make sure to use the right type signature (will change for .NET 4)
IHttpHandlerFactory fact = (IHttpHandlerFactory)Activator.CreateInstance(Type.GetType("System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"));
IHttpHandler handler = fact.GetHandler(context, context.Request.RequestType, context.Request.RawUrl, context.Request.PhysicalApplicationPath);
try
{
// This will trap your asmx Exception and output 500 status and soap fault
handler.ProcessRequest(context);
// force 200 status for Silverlight to receive fault code
context.Response.StatusCode = 200;
context.ApplicationInstance.CompleteRequest();
}
finally
{
fact.ReleaseHandler(handler);
}
}
}
After creating your IHttpHandler, register it on your .ASMX website web.config
<add verb="*" path="*.asmx" validate="false" type="CrmSilverlightHttpHandler.SilverlightSoapFaultHandler, CrmSilverlightHttpHandler, Version=1.0.0.0, Culture=neutral, PublicKeyToken=*" />
This will basically make every single request to asmx webservices return HTTP 200, no matter what.
By now, if you run your Silverlight client you’ll probably stop getting the super annoying "The remote server returned an error: NotFound." response.
Good. Now all we have to do is get the proper fault details on your asynchronous Silverlight request. Simple:
if (e.Error == null)
{
}
else if (e.Error is FaultException)
{
FaultException fault = e.Error as FaultException;
MessageFault messageFault = fault.CreateMessageFault();
if (messageFault.HasDetail)
{
string description = messageFault.GetDetail<XElement>().Element("description").Value;
string code = messageFault.GetDetail<XElement>().Element("code").Value;
string type = messageFault.GetDetail<XElement>().Element("type").Value;
}
}
If you want things really tidy (I didn’t had time for this, sorry), try to write your own error descriptor and use FaultException<T>.
Happy Silverlight coding!
Good reading:
Creating and Handling Faults in Silverlight
https://msdn.microsoft.com/en-us/library/dd470096(VS.96).aspx
Data Performance and Fault Strategies in Silverlight 3
https://msdn.microsoft.com/en-us/magazine/ee294456.aspx
Comments
Anonymous
May 13, 2010
Interesting article. I have an ashx handler that I need to return Exception details to a Silverlight application. I tried to use your technique of setting Response.StatusCode = 200 just before the point where the Exception is thrown and I can see via Fiddler that this works. However when I try to get to the error details in the app using webRequest.EndGetResponse I get the same old 500 error. Any ideas how I can get this to work?Anonymous
March 27, 2011
I add Your code to my app but it does not work. Do You have some source code ?