Developing with SilverLight 4.0 and WCF for the service side, I wanted to do the following:
1- For known/expected service side exception, I want the user to have a clear feedback with the error message shown to him
2- For all exceptions, and for development scenarios, I want the full exception message displayed back to the user.
I used to do that very easily with rich client (WPF) + WCF service. You indeed just need to add the following behavior, server side, to your service:
<behavior name="metadataAndDebug"> <serviceDebug includeExceptionDetailInFaults="true"/> </behavior>
Using SilverLight however, this is not enough. Even with the behavior set, you get the following error message at the client level
the server returned an error : not found
Not very useful... After some research I found out this is due to a limitation of web browsers and the HTTP stack: By default, WCF services return fault messages with an HTTP 500 response code. Due to limitations in the browser networking stack, the bodies of these messages are inaccessible within Silverlight, and consequently the fault messages cannot be read by the client.
This source from Microsoft explains two workarounds to the issue:
http://msdn.microsoft.com/en-us/library/ee844556(VS.95).aspx
The one I used is the following:
Modify the HTTP status code: You can modify your service to return SOAP faults with an HTTP status code of 200, Silverlight 4 so that faults will be processed successfully. How to do this is outlined below. Note that this will make the service non-compliant with the SOAP protocol, because SOAP requires a response code in the 400 or 500 range for faults. If the service is a WCF service, you can create an endpoint behavior that plugs in a message inspector that changes the status code to 200. Then you can create an endpoint specifically for Silverlight consumption, and apply the behavior there. Your other endpoints will still remain SOAP-compliant.
This is done by create the following behavior extension:
public class SilverlightFaultBehavior : BehaviorExtensionElement, IEndpointBehavior { public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { SilverlightFaultMessageInspector inspector = new SilverlightFaultMessageInspector(); endpointDispatcher.DispatchRuntime.MessageInspectors.Add(inspector); } public class SilverlightFaultMessageInspector : IDispatchMessageInspector { public void BeforeSendReply(ref Message reply, object correlationState) { if (reply.IsFault) { HttpResponseMessageProperty property = new HttpResponseMessageProperty(); // Here the response code is changed to 200. property.StatusCode = System.Net.HttpStatusCode.OK; reply.Properties[HttpResponseMessageProperty.Name] = property; } } public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext) { // Do nothing to the incoming message. return null; } } // The following methods are stubs and not relevant. public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { } public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { } public void Validate(ServiceEndpoint endpoint) { } public override System.Type BehaviorType { get { return typeof(SilverlightFaultBehavior); } } protected override object CreateBehavior() { return new SilverlightFaultBehavior(); } }
And registering server side this way:
<system.serviceModel> <extensions> <behaviorExtensions> <add name=”silverlightFaults” type=”Microsoft.Silverlight.Samples.SilverlightFaultBehavior, SilverlightFaultBehavior, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null”/> </behaviorExtensions> </extensions> <behaviors> <endpointBehaviors> <behavior name=”SilverlightFaultBehavior”> <silverlightFaults/> </behavior> </endpointBehaviors> </behaviors> <services> <service name=”Calculator.Web.Service”> <endpoint address=”” binding=”basicHttpBinding” contract=”Calculator.Web.Service” behaviorConfiguration=”SilverlightFaultBehavior” /> </service> </services> </system.serviceModel>
Warning: There was an issue in SilverLight 3.0 which is still not fixed in SilverLight 4.0:
The Type for the extension has to be specified in one line, with the correct number of white spaces... type definition is checked as string comparison rather that Type comparison... Be aware of that!
Comments
You can follow this conversation by subscribing to the comment feed for this post.