Propagating Fault Exception to Silverlight Client

Sathish DVSenior Software Engineer
Published:
While working on Silverlight and WCF application, I faced one issue where fault exception occurred at WCF operation contract is not getting propagated to Silverlight client. So after searching net I came to know that it was behavior by default for silverlight client. And these issues can be addressed by little tweak. So, here I am writing on how to propagate fault exception from service to silverlight client.

Reason for this kind of behavior is if any fault exception is raised at operation contract, then the exception is converted to SOAP faults and returned to the client. Since the networking in Silverlight is performed based on browser's HTTP stack. But this limitation is applicable to Silverlight 2. In Silverlight 3, the networking is performed using browser HTTP stack by default. But the new client HTTP stack allows you to bypass the browser and perform networking operation through operating system.

In Silverlight 2, SOAP faults cannot be propagated to client side because due to limitations in silverlight, it cannot access some of the messages in the browser HTTP stack bodies. So HTTP error code 500 which holds the SOAP faults is converted to 404(Page not found), and same is returned to client. So obviously client will be receiving "Remote Server not found"  exception.

In Silverlight 3, this limitation is solved. Since Silverlight 3 uses client HTTP stack, it is simple that networking is performed by API's exposed by operating system itself. So you can tell Silverlight to use the client HTTP stack for requests made, instead of using browser HTTP stack. Below is the code use to inform the silverlight to use client http stack for requests call made for sites begin with http://.
HttpWebRequest.RegisterPrefix("http://", WebRequestCreator.ClientHttp);

Open in new window


Adding the above line code will make all subsequent call starts with http:// to client HTTP stack.

To support for specific site then add the below code
HttpWebRequest.RegisterPrefix("http://xxxx.com", WebRequestCreator.ClientHttp);

Open in new window



Ok, here another question kicked off my mind. What if my Silverlight client is creating web request to WCF service via proxies created at my client side and Silverlight is intended to receive SOAP faults regardless of the address. So do I need to extend my WCF behaviors, so that WCF service will be intelligent enough to convert the http error codes before sending back to client? The answer is YES. Here I will explain on how to achieve this.

My Service Contract and Operation Contract is defined as shown below

 [ServiceContract]
                          public interface IService1
                          {
                              [OperationContract]
                              [FaultContract(typeof(ValidationException))]
                              string getData();
                          }

Open in new window


Data contract class which define data member with some validation rules. StringLength validator is available in System.ComponentModel.DataAnnotations.

 [DataContract]
                          public class MyDataContract
                          {
                              [DataMember]
                              [StringLength(10, ErrorMessage="String length should not be greater than 10")]
                              public string Name { get; set; }
                          }

Open in new window


Contracts implemented in Service class

public class Service1 : IService1
                          {
                              
                              public string getData()
                              {
                                  MyDataContract dc = new MyDataContract();
                                  dc.Name = "12345678901"; // string length greater than 10
                                  return dc.Name;
                              }
                          }

Open in new window


here getData() method throws FaultException of type ValidationException, which inturn converted to SOAP fault. So in order to propagate the SOAP fault to silverlight client we need to extend the endpoint behavior so that SOAP faults can be sent to silverlight client. Below are the steps:

1.) Create a class which is inherited from System.ServiceModel.Configuration.BehaviorExtensionElement and also implemets System.ServiceModel.Description.IEndpointBehavior.

 public class SilverlightFaultContractBehavior : BehaviorExtensionElement, IEndpointBehavior
                      
                          {
                              public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
                              {
                                  SilverlightFaultMessageInspector faultnspector = new SilverlightFaultMessageInspector();
                                  endpointDispatcher.DispatchRuntime.MessageInspectors.Add(faultnspector);
                              }
                      
                              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)
                                  {
                                      // Dont do anything to incoming request. 
                                      return null;
                                  }
                      
                      
                              }
                      
                              // The following methods are not relevant. So doing dummy implementation of  IEndpointBehavior interface
                      
                              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(SilverlightFaultContractBehavior); }
                              }
                      
                              protected override object CreateBehavior()
                              {
                                  return new SilverlightFaultContractBehavior();
                              }
                      
                          }

Open in new window


2.) Do the appropriate changes to web.config file.

<system.serviceModel>
                            <extensions>
                              <behaviorExtensions>
                                <add name="silverlightFaults"
                                     type="SilverlightApplication1.Lib.SilverlightFaultContractBehavior, 
                                   SilverlightFaultContractBehavior, 
                                   Version=1.0.0.0, 
                                   Culture=neutral, 
                                   PublicKeyToken=null"/>
                              </behaviorExtensions>
                            </extensions>
                      
                            <behaviors>
                              <endpointBehaviors>
                                <behavior name="SilverlightFaultBehavior">
                                  <silverlightFaults/>
                                </behavior>
                              </endpointBehaviors>
                      
                              <serviceBehaviors>
                                      <behavior name="">
                                          <serviceMetadata httpGetEnabled="true" />
                                          <serviceDebug includeExceptionDetailInFaults="false" />
                                      </behavior>
                                  </serviceBehaviors>
                              </behaviors>
                           
                            <services>
                              <service name="SilverlightApplication1.Web.Service1">
                                <endpoint address=""
                                          binding="basicHttpBinding"
                                          contract="SilverlightApplication1.Web.IService1"
                                          behaviorConfiguration="SilverlightFaultBehavior" />
                              </service>
                            </services>
                      
                            <serviceHostingEnvironment aspNetCompatibilityEnabled="True" multipleSiteBindingsEnabled="true" />
                          </system.serviceModel>

Open in new window


3.) Client code:
 SilverlightApplication1.ServiceReference1.Service1Client client = new SilverlightApplication1.ServiceReference1.Service1Client();
                                  client.getDataCompleted += new EventHandler<getDataCompletedEventArgs>(client_getDataCompleted);
                                  client.getDataAsync();
                      
                       void client_getDataCompleted(object sender, getDataCompletedEventArgs e)
                              {
                                  if (e.Error != null)
                                  {
                                      if (e.Error is FaultException)
                                      {
                                          MessageBox.Show(e.Error.Message);
                                      }
                                  }
                              }

Open in new window


This is how you can propagate Fault Exceptions to Silverlight Client.

Any feedback and suggestions is highly recommended!!!!!!!!

Thanks......
0
5,184 Views
Sathish DVSenior Software Engineer

Comments (0)

Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.