views:

335

answers:

2

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"&gt;
 <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?

A: 

No client ever gets exceptions from web services. Web services don't send exceptions - they send faults.

The details of the fault are contained in the <detail/> element of the fault message. some platforms, including WCF, parse this information in order to translate from the fault to a platform-specific exception.

Since there is no information in the <detail/> element, no translation is likely to occur.

John Saunders
i did say exception/fault :-)so i will have to convert to .svc to get the fault details?
Simon_Weaver
A: 

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);
    }
}
Sichbo
easier to switch over to true WCF i think! thanks for the handler
Simon_Weaver