restweb-serviceswcfexceptionwcf-rest

Exception Handling in WCF REST Full Service


I am developing REST Full API using WCF Service 4.5 F/W. Please suggest how to send exception or any business validation messages to client. I am looking for a very generic solution please suggest the best ways of doing it. I have tried some approaches below,

  1. Set OutgoingWebResponseContext before sending response to client.

  2. Defined Fault contract that is working fine only Adding service reference(proxy class) not working in REST FULL environment.

  3. Adding WebFaultException class in catch block.

  4. WCF Rest Starter Kit - I got some articles and posts regarding this but their CodePlex official sit suggested no longer this available. link. So, I don't want to go with this.

These are not working as expected.. My sample Code Snippet: Interface:

    [OperationContract]
    [FaultContract(typeof(MyExceptionContainer))]
    [WebInvoke(Method = "GET", UriTemplate = "/Multiply/{num1}/{num2}", BodyStyle = WebMessageBodyStyle.Wrapped,RequestFormat = WebMessageFormat.Xml, ResponseFormat = WebMessageFormat.Xml)]
    string Multiply(string num1, string num2);

Implementation:

         public string Multiply(string num1, string num2)
    {
        if (num1 == "0" || num2 == "0")
        {
            try
            {
                MyExceptionContainer exceptionDetails = new MyExceptionContainer();
                exceptionDetails.Messsage = "Business Rule violatuion";
                exceptionDetails.Description = "The numbers should be non zero to perform this operation";
                //OutgoingWebResponseContext outgoingWebResponseContext = WebOperationContext.Current.OutgoingResponse;
                //outgoingWebResponseContext.StatusCode = System.Net.HttpStatusCode.ExpectationFailed;
                //outgoingWebResponseContext.StatusDescription = exceptionDetails.Description.ToString();
               // throw new WebFaultException<MyExceptionContainer>(exceptionDetails,System.Net.HttpStatusCode.Gone);
                throw new FaultException<MyExceptionContainer>(exceptionDetails,new FaultReason("FaultReason is " + exceptionDetails.Messsage + " - " + exceptionDetails.Description));
            }
            catch (Exception ex)
            {
                throw new FaultException(ex.Message);
            }
        }

        return Convert.ToString(Int32.Parse(num1) * Int32.Parse(num2));
    }

Web.Config :

  <system.serviceModel>
<services>
  <service name="TestService.TestServiceImplementation" behaviorConfiguration="ServiceBehaviour">
    <endpoint binding="webHttpBinding" contract="TestService.ITestService" behaviorConfiguration="webHttp" >
    </endpoint>
  </service>
</services>
<behaviors>
  <serviceBehaviors>
    <behavior name="ServiceBehaviour">
      <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
      <serviceMetadata httpGetEnabled="true"/>
      <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
      <serviceDebug includeExceptionDetailInFaults="true"/>
    </behavior>
  </serviceBehaviors>
  <endpointBehaviors>
    <behavior name="webHttp" >
      <webHttp helpEnabled="true" faultExceptionEnabled="true"/>
    </behavior>
  </endpointBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />

Client :

try
        {
            string serviceUrl = "http://localhost:51775/TestService.cs.svc/Multiply/0/0";
            //Web Client
            //WebClient webClient = new WebClient();
            //string responseString = webClient.DownloadString(serviceUrl);
            WebRequest req = WebRequest.Create(serviceUrl);
            req.Method = "GET";
            req.ContentType = @"application/xml; charset=utf-8";
            HttpWebResponse resp = req.GetResponse() as HttpWebResponse;
            if (resp.StatusCode == HttpStatusCode.OK)
            {
                XmlDocument myXMLDocument = new XmlDocument();
                XmlReader myXMLReader = new XmlTextReader(resp.GetResponseStream());
                myXMLDocument.Load(myXMLReader);
                Console.WriteLine(myXMLDocument.InnerText);
            }
            Console.ReadKey();
        }
        catch (Exception ex)
        { 
        Console.WriteLine(ex.Message);
        }

This is my first Question, Thank You to All Passionate Developers..!


Solution

  • Instead of FaultException, use the following:

    Server:

    catch (Exception ex)
                {
                    throw new System.ServiceModel.Web.WebFaultException<string>(ex.ToString(), System.Net.HttpStatusCode.BadRequest);
                }
    

    The Client:

    catch (Exception ex)
                {
                    var protocolException = ex as ProtocolException;
                    var webException = protocolException.InnerException as WebException;
                    if (protocolException != null && webException != null)
                    {
                        var responseStream = webException.Response.GetResponseStream();
                        var error = new StreamReader(webException.Response.GetResponseStream()).ReadToEnd();
                        throw new Exception(error);
                    }
                    else
                        throw new Exception("There is an unexpected error with reading the stream.", ex);
    
                }