R – Can Silverlight WCF client read exceptions from an ASMX web service

asmxsilverlightwcf

I've seen no need to upgrade my services to WCF, but I have been using WCF clients for some time to access ASMX services from .NET 3.5 ASP.NET. I figured eventually I'd hit a wall in this mismatch and I just did – but with Silverlight.

When using Silverlight to access ASMX web services I get an error like this in a popup :

An exception occurred during the
operation, making the result invalid.
Check InnerException for exception
details.

If I'm debugging I get this error :

 The remote server returned an error: NotFound.

If I look in Fiddler the exception/fault is there just fine :

 <?xml version="1.0" encoding="utf-8"?>
 <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 <soap:Body><soap:Fault>
 <faultcode>soap:Server</faultcode>
 <faultstring>Server was unable to process request. ---&gt; ID does not match</faultstring>
 <detail /></soap:Fault></soap:Body></soap:Envelope>

How do I actually get to this exception in the Silverlight client.

I need the error to be accessible at runtime with no fiddler and no debugger.

There is a property includeexceptiondetailinfaults that belongs in <behaviors> in the web.config – but this is for server side only as far as I can tell.

Am I correct in assuming that I will need to convert my asmx to svc to be able to get actual exception details in the silverlight client?

Best Answer

If you're happy to wrap the asmx SOAP request in your own IHttpHandler, you can force-feed a Response.StatusCode = 200 after the System.Web.Script.Services.ScriptHandlerFactory does it's work. Here's a sample;

static void ProcessService(HttpContext context)
{
    //
    // I'm also using this to fake/hide the path of my asmx so that 
    // domain.com/xml becomes the service end-point..
    //
    string asmx = "/Services/Some.Service.asmx";
    string method = context.Request.Path.Substring("/xml".Length);

    //
    // ScriptHandlerFactory and friends are sealed so have to use reflection..
    //
    IHttpHandlerFactory fact = (IHttpHandlerFactory)Activator.CreateInstance(Type.GetType("System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions"));
    Type vpt = Type.GetType("System.Web.VirtualPath, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
    System.Reflection.MethodInfo mi = vpt.GetMethod("Create", new Type[] { typeof(string) });
    object vp = mi.Invoke(null, new object[] { context.Request.Path });
    System.Reflection.FieldInfo fi = context.Request.GetType().GetField("_pathInfo", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
    System.Reflection.FieldInfo _virtualPath = vpt.GetField("_virtualPath", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
    _virtualPath.SetValue(vp, method);
    fi.SetValue(context.Request, vp);
    IHttpHandler handler = fact.GetHandler(context, context.Request.RequestType, asmx, context.Server.MapPath(asmx));

    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);
    }
}
Related Topic