Pages

Men

rh

10/29/2014

Handle errors in WCF with and without FaultContract attributes.

Introduction

In this tip I am going to discuss about the error handling in WCF (Windows communication foundation).Everybody wants the simple things , i mean how they can understand easily or how they can do it efficiently in easy way. So if we talk about the Faults in WCF services  , that(Faults) can not be send  to the Client directly in the SOAP message without the help of the FaultException Class. So the Client will able to see the WCF faults in browser itself but the error messages related to the faults should be simple or  it can be understandable by the client easily. So it can be handle by WCF FaultContract attribute easily. So we need to use both FaultException class to through the faults to the client and  FaultContract attributes to make the fault message  as simple as possible.

Background

 Basically this tip is for newbie. In this article I am going to elaborate the concept of FaultContract attribute in  WCF.  So here I will provide some examples and you can also download the same application in a  zip file  format.
  The programmers/ readers should have some  basic idea or knowledge about the WCF services like how to create WCF service application, how to consume the WCF services in the client application and  how to call it in the client application etc etc.
FaultContract attribute is basically used in a method as an attribute. By using this attributes , we can add more information in our WCF faults. The FaultContract is defined as class type in the attribute. So if we add a class type in the FaultContract we will able to throw the FaultException of type FaultContract.  So later in this tip we will show you the complate example of FaultContract with type.
 So lets start our journey on the erro handling in WCF services.

Using the code

 As we discussed above that the tip is completely about the faults/errors handling in  WCF services . So in our upcoming examples we will use FaultException class to handle the errors. But to add more information in the  fault to make , we are using the FaultContract  attributes in the method . So lets start...
Here we will check  two examples as per our requirement.
 A.  In first Example we will handle the WCF faults without  FaultContract attributes.
 B.  In second Example we will handle the WCF faults with  FaultContract attributes.
 A.  In first Example we will handle the WCF faults without  FaultContract attributes.

   Step : 1    

    Lets create a Wcf service application in your Visual studio framework  and name it as "HandleFaultInWCF". After adding a service application some  files will be create like IService1.cs  and Service1.svc.cs

   Step : 2

   After adding the WCF service application two file will be create like IService1.cs and Service1.svc.cs.  This file  IService1.cs  act as a service contract . Service contract is nothing but it just encapsultes the all the contract and as per the client requirement it just exposes its contract. Actually it is a interface so as per the interface defination it just includes the declaration part of all the contract.  Then add this much of code in your cs file like IService1.cs file.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace HandleFaultInWCF
{
   
    [ServiceContract]
    public interface IService1
    {
        // Here we are handling the Fault without FaultContract attribute
        [OperationContract]
        string GetData(string value);

    }
}

In this above code I have just declared a method/operationcontract  "GetData()" in the IService1 interface and just added one attribute [OperationContract].

Step : 3

 Then in step 3 we will just define the GetData() method/operationcontract in the  svc.cs  file like Service1svc.cs file.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using System.Data.SqlClient;

namespace HandleFaultInWCF
{
    public class Service1 : IService1
    {
      

        // Return the  Value what ever entered in the client end
        public string GetData(string value)
        {
            try
            {
                // Assign a conection string
                SqlConnection conObj = new SqlConnection("Server=localhost; Database=OnlineShopping ; Integrated Security=True");
             
                // Open the connection
                conObj.Open();

                return value;
            }
            catch (Exception ex)
            {
                throw new FaultException(ex.Message);
            }
        }
    }
}

In GetData() method we are trying to opening a datbase and if  we will not able to open the database then exception will thrown by Faultexception class in catch block. The catch block will simply through the exception message to the client. So the client will directly see the sytem generated message , There is no such user friendly message by which the client can easily understand. So it will be little bit confusing for the client/end user what to do. We will check the output of the method in later of the tip.
As we are unable to give/show the user friendly message to client/end user in above senario. But in our next examples we will use the FaultException with FaultContract attributes and we will able  send any type of message or details of the message in client/end user side.
 B.  In second Example we will handle the WCF faults with  FaultContract attributes.

       Step  1:

         We can use the example B in the same service , then add this much of code in your cs file like IService1.csfile inside your ServiceContract. So now the new code looks like
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace HandleFaultInWCF
{
   
    [ServiceContract]
    public interface IService1
    {

        // Handling the Fault with FaultContract attribute as Strong Type 
        [OperationContract]
        [FaultContract(typeof(SetErrorDetails))]
        int DividedByZero(int firstNumber,int secondNumber);

          // Here we are handling the Fault without FaultContract attribute
        [OperationContract]
        string GetData(string value);
    }

    // Declared the Data Contract for handling the fault details
    [DataContract]
    public class SetErrorDetails
    {
        public string erroName;
        public string errorDetails;

        [DataMember]
        public string ErrorName
        {
            get
            {
                return erroName;
            }

            set
            {
                erroName = value;
            }
        }

        [DataMember]
        public string ErrorDetails
        {
            get
            {
                return errorDetails;
            }

            set
            {
                errorDetails = value;
            }
        }

    }

}
 
 In above code we have declared one method "DividedByZero()" and one class SetErrorDetails class.
This method DividedByZero() has two attributes   [OperationContract] and [FaultContract(typeof(SetErrorDetails))].  By using this FaultContract attributes we will be able send some  user understandable message   to the  end user/ client.  [FaultContract(typeof(SetErrorDetails))] means the FaultContract is SetErrorDetails class types and we have also declared the class of some property.
 Here I have declared the class SetErrorDetails and has two property like ErrorName and ErroDetails.  We will use this class in the FaultContract Type. So in this case the property  ErrorName  we will set name of the error and another property  ErrorDetails is used for setting the details of the error. But if we compare the Example A , there was no such facility to set the any message details in the FaultContract attributes.

Step  2:

 Then in step 3 we will just define the DividedByZero() method in the  svc.cs  file like Service1svc.cs file. After adding the code the file looks like this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using System.Data.SqlClient;

namespace HandleFaultInWCF
{
    public class Service1 : IService1
    {
     // Return the  Value what ever entered in the client end
         public string GetData(string value)
        {
            try
            {
                // Assign a conection string
                SqlConnection conObj = new SqlConnection("Server=localhost; Database=OnlineShopping ; Integrated Security=True");
             
                // Open the connection
                conObj.Open();

                return value;
            }
            catch (Exception ex)
            {
                throw new FaultException(ex.Message);
            }
        }

        // Checking the Fault as strong Type
        public int DividedByZero(int FirstNumber, int SecondNumber)
        {
            try 
         {  
             return (FirstNumber / SecondNumber);
         }

         catch (Exception ex)
         {
                // Creating the ErrorDetails Class Object 
                 SetErrorDetails errorObj = new SetErrorDetails();

                 if (SecondNumber == 0)
                {
                    // Here we can set the message what ever we want to show in Client side
                    errorObj.ErrorName = "The second number is Zero.";
                    errorObj.ErrorDetails = ex.Message + " " + "Second number must be greater than Zero"; 
                }
                 throw new FaultException<seterrordetails>(errorObj);
         }

        }
    }
}

</seterrordetails>
 Here we  declared the method/operationcontract DividedByZero() . In this method we are just trying to return some  integer value after dividing two integer number. Here we are just handling the error if the second number will be Zero(0).
How we will set more information in the FaultContract:
 In this above method we are handling the fault in catch block if the secondNumber = 0 . In the Catch block we creating the object of SetErrorDetails class and assigning  some user understandable message  to the property of SetErrorDetails  class. In this example I have assigned like this
errorObj.ErrorName = "The second number is Zero.";

errorObj.ErrorDetails = ex.Message + " " + "Second number must be greater than Zero";
You can set any text in this class property and I am throughing the  FaultException by this statement throw new FaultException(errorObj) . So here errorObj is the class SetErrorDetails object. So in the client side we have to also handle the FaultException with SetErrorDetails  type.

 Consuming the service in the client application :

  To consume the service in the client application , first build the service application and then add the service reference in the client app like  "ClientApp". In the client application add a page like WebForm1.aspx  and put the html code   in WebForm1.aspx  page.
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="ClientApp.WebForm1" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>  
          <h2>WCF Fault Without FaultContract</h2>
      <h3> Please Enter some string :</h3> <asp:TextBox ID="txtEnter" runat="server"></asp:TextBox>
         <asp:Button ID="btnResult1"  runat="server" Text="GetData() Method" OnClick="btnResult1_Click" />
         <h4>Result:</h4>
        <asp:Label ID="lblResult1" runat="server" ForeColor="Red" ></asp:Label>
         
         <h2>WCF Fault With FaultContract</h2>
        
        Enter First Number : <asp:TextBox ID="txtFirst" runat="server" Text="1"></asp:TextBox>
        Enter Second Number : <asp:TextBox ID="txtSecond" runat="server" Text="0"></asp:TextBox>
        <asp:Button ID="btnCheckResult"  runat="server" Text="DividedByZero() method" OnClick="btnCheckResult_Click" />
        
         <h4>Result:</h4>
        <asp:Label ID="lblResult2" runat="server"></asp:Label><br />

        <asp:Label ID="lblError1" runat="server" ForeColor="Red" ></asp:Label>
        <asp:Label ID="lblError2" runat="server" ForeColor="Red" ></asp:Label>

    </div>
    </form>
</body>
</html>
Put the code in the code behind file WebForm1.aspx.cs file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ServiceModel;
using ClientApp.ServiceReference1;

namespace ClientApp
{
    public partial class WebForm1 : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }

        protected void btnCheckResult_Click(object sender, EventArgs e)
        {
            ServiceReference1.Service1Client serviceobj = new ServiceReference1.Service1Client();
            int result = 0;

            try
            {
               
                result = serviceobj.DividedByZero(Convert.ToInt16(txtFirst.Text),
                                                  Convert.ToInt16(txtSecond.Text));

                lblResult2.Text = Convert.ToString(result);

            }
            catch (FaultException<seterrordetails> exObj)
            {
                 lblError1.Text = Convert.ToString(exObj.Detail.ErrorName);
                 lblError2.Text = Convert.ToString(exObj.Detail.ErrorDetails);  
            }
        }

        protected void btnResult1_Click(object sender, EventArgs e)
        {
            ServiceReference1.Service1Client serviceobj = new ServiceReference1.Service1Client();

            try
            {
                lblResult1.Text = serviceobj.GetData(txtEnter.Text.Trim());
                
            }
            catch (FaultException ex)
            {
                lblResult1.Text = ex.Message;
            }
        }
    }
}
</seterrordetails>
 I have added both example A (In first Example we will handle the WCF faults without  FaultContract attributes.)  and example B (In second Example we will handle the WCF faults with  FaultContract attributes. )code in the same code behind file. Now run the service consumed client application . After running the application the output would be like this:

Lets describe about the output:

 In the output window there would be two examples .
 Step to check the Example A (WCF Fault Without FaultContract):
 1. Enter some text on the textbox "Please Enter some string".
 2.   Then click on the First button "GetData() Method" then you will see the  output for example A.
 The output will be:
"Cannot open database "OnlineShopping" requested by the login. The login failed. Login failed for user 'ram\ram1'." This is the exception message which is generated from system. In this example we are not sending any message from the service.
 Step to check the Example B (WCF Fault With FaultContract):
 1. Suppose enter some integer value "1" in the First textbox "Enter First Number".
 2. Suppose enter some integer value "0" in the Second textbox "Enter Second Number".
 Note :
 Please provide Zero(0) in the second example to check the exception.
Then to check the example B output, you need to click on the second button  "DividedByZero() method". For starting i have given some values like "1" and "0" to the respective textbox like "Enter First Number" and  "Enter Second Number" . The output will be :
 The second number is Zero. Attempted to divide by zero. Second number must be greater than Zero.
In this message we have added some user friendly message to make clear to the end user about the faults and we just did it using the FaultContract attribute in the FaultException class.
So eventually we can say that if you want to give some infromation about the fault to the enduser then better to use FaultContract attribute with FaultException class.
Hope you will enjoy this tip . I am coming with some new Tips about WCF.

Source from
http://www.codeproject.com/Tips/833082/Handle-errors-in-WCF-with-and-without-FaultContrac

No comments :

Post a Comment