Exception Handling in WCF REST Full Service
Asked Answered
B

3

5

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..!

Bechler answered 27/9, 2014 at 2:38 Comment(0)
A
11

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);

            }
Angulate answered 28/9, 2014 at 13:3 Comment(3)
Thanks for your reply. I have tried with WebFaultException but no luck Still I could not get the actual exception in client sideBechler
@SJAlex Refer to my update how I get catch and handle the exception. There are other ways also by casting the exception but I do it like this.Annabel
I had to call responseStream.Seek(0, System.IO.SeekOrigin.Begin); For some reason the stream wasn't at the beginning position.Exergue
F
1

Creating true rest in wcf is next to impossible, but leveraging parts of the httpprotocol is of course possible.

To control the error messages in your service you will have to provide an error handler (an I errorhandler implementation ) which hooks into the wcf stack and overrides whatever error handling is defined here.

This interface contains two methods. One which informs wcf if it can handle a certain exception (bool HandleError) and another invoked if HandleError returns true. This second method ProvideFault let's you define how to respond to the client in case of exceptions.

You can chain handlers to get more granularity. And since you are doing rest you should probably use the httpstatus codes to inform about the error conditions where applicable.

http://blogs.msdn.com/b/carlosfigueira/archive/2011/06/07/wcf-extensibility-ierrorhandler.aspx

http://www.remondo.net/wcf-global-exception-handling-attribute-and-ierrorhandler/

Forecourse answered 27/9, 2014 at 7:31 Comment(0)
L
-1

Web.Config :

<system.serviceModel>
   <services>
    <service name="TestService.TestServiceImplementation">
      <endpoint address=""
                binding="webHttpBinding"
                contract="TestService.Service.ITestServiceImplementation" />
    <service/>
  <services/>
    <behaviors>
      <serviceBehaviors>
        <behavior>         
          <serviceMetadata httpGetEnabled="true"/>         
          <serviceDebug includeExceptionDetailInFaults="true"/>
        <behavior/>
      <serviceBehaviors/>
    <behaviors/>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  <system.serviceModel/>
 <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>   
    <directoryBrowse enabled="true"/>
  <system.webServer/>

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 (FaultException ex)
        {
            throw new FaultException(ex.Message);
        }
    }

    return Convert.ToString(Int32.Parse(num1) * Int32.Parse(num2));
}
Libreville answered 15/10, 2018 at 6:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.