In this article, we are going to see, how to use the Fault contracts in WCF programming.
What is WCF?
WCF (Windows Communication Foundation) is a .NET dedicated communication framework. WCF provides an easy way to expose our methods as services and consuming the existing services as traditional methods. (More about the WCF can be found in my previous article: WCF Programming for Beginners.)
What are SOAP Faults?
In all managed applications we use the Exception objects to handle the errors. Similarly in WCF programming also to handle the errors and convey that error information from service to client and client to service we use the SOAP faults. FaultContractAttribute, which is defined in the namespace: System.ServiceModel.FaultContractAttribute, is used to declare customized SOAP faults.
SOAP Faults mainly of two types:
- Declared SOAP faults. - These are the SOAP faults that are specified on the operations by using the FaultContractAttribute.
- Undeclared SOAP faults. - These are SOAP faults that occurs in the operations but are not specified on the operations by using the FaultContractAttribute.
- [AttributeUsageAttribute(AttributeTargets.Method, AllowMultiple = true, Inherited = false)]
- public sealed class FaultContractAttribute : Attribute
Listing 1: Fault Contract Attribute Syntax
Creating Customized SOAP Faults
To create the customized SOAP faults:
- Declare and define the structure for our customized SOAP fault.
- Attach the customized SOAP fault to the operations by using the FaultContractAttribute.
- Check for the error condition and raise the Customized SOAP fault in service operations.
- Handle the SOAP faults at the client side.
Here I am going to explain all the above steps by using a sample WCF Service.
Sample Program:
Let us take a WCF service, which has a small function "GetEmpDetails (string EmpID) ". This function accepts empid as input parameter and check for that employee record against the DB. If the employee record exists then it returns that record, if not then it should through a custom fault message to the client, saying that "Employee Record does not exist".
- String GetEmpDetails( string EMPID)
- {
-
-
-
- }
STEP 1: Create the Custom Fault Message Definition.
In this sample program we are going to create custom SOAP Fault that contains an error message string property.
In WCF we have to use the DataContractAttribute, DataMemberAttribute to expose the properties /variable/ events /indexes from WCF service to clients.
-
-
-
-
- [DataContract]
- public struct CustomFaultMsg
- {
-
-
-
-
- [DataMember]
- public string MyCustomErrMsg { get; set; }
- }
Listing 2: Custom Fault Message Structure
STEP 2: Attach the SOAP fault on the operation
To make use of the fault messages in our SOAP messages we have attach them to the operations by using "FaultContractAttribute".
-
-
-
- [ServiceContract]
- public interface IService
- {
-
-
-
-
-
-
-
-
- [OperationContract]
- [FaultContract(typeof(CustomFaultMsg))]
- Employee GetEmpDetails(string EmpId);
- }
"FaultContract[typeof(<<Fault>>)] " attribute is used to add a custom fault to an operation. In this example, we are adding a custom fault of type "CustomFaultMsg".
"CustomFaultMsg" is structure for our custom fault. (This is defined in step1).
Here function return type "Employee" is an employee structure. "DataContract" attribute is used to expose this structure in service.
-
-
-
- [DataContract]
- public struct Employee
- {
- [DataMember]
- public string FName { get; set; }
- [DataMember]
- public string LName { get; set; }
- [DataMember]
- public string DeptID { get; set; }
- [DataMember]
- public string MailID { get; set; }
- [DataMember]
- public string Zip { get; set; }
- }
STEP 3: Check for the error condition and raise the customized SOAP fault message:
In the sample program, IService interface is implemented by a class Service. Here the method GetEmpDetails() should raise our own customized exception, whenever it fails to find the employee details.
-
-
-
-
-
-
-
- public Employee GetEmpDetails(string EmpId)
- {
-
-
- var empRecord = from dr in ds.Tables[0].AsEnumerable()
- where dr["EmpId"].ToString() == EmpId
- select dr;
-
- if (empRecord.Count() == 0)
- {
-
-
- CustomFaultMsg custmErr = new CustomFaultMsg {
- MyCustomErrMsg = "There is no employee exist with the emp id : " + EmpId
- };
-
- throw new FaultException < CustomFaultMsg > (custmErr);
- }
-
- else
- {
-
-
- Employee objEmp = new Employee();
- foreach(DataRow dr in empRecord)
- {
-
-
- objEmp.FName = dr["FirstName"].ToString();
- objEmp.LName = dr["LastName"].ToString();
- objEmp.DeptID = dr["DeptId"].ToString();
- objEmp.MailID = dr["MailId"].ToString();
- objEmp.Zip = dr["ZipCode"].ToString();
- }
-
- return objEmp;
- }
- }
Listing 3: Sample Program at WCF Service End
In this function, the following LINQ technology is used to search for the emp in the existing data set.
- var empRecord = from dr in ds.Tables[0].AsEnumerable()
- where dr["EmpId"].ToString() == EmpId
- select dr;
Error Condition: if (empRecord.Count() == 0) is used to throw the custom falut message. Whenever there is an unsuccessful search for the emp, then this condition become true. And here we are going to initialize the object for our customized fault message and throws the exception to the client.
- CustomFaultMsg custmErr =
- new CustomFaultMsg { MyCustomErrMsg = "There is no employee exist with the emp id : " + EmpId };
- throw new FaultException<CustomFaultMsg>(custmErr);
Host this sample Service on IIS under a virtual directory folder Named "WCFService". Once this service is hosted, next step is to consume the service by the client.
STEP 4: Handling the SOAP Fault messages in the client program
Here in the client-side while consuming this service use the try and catch blocks to catch the SOAP faults. In Catch blocks, the exception object type should match with our customized SOAP fault created in step1.
Create a client project and add the service reference to our WCFService hosted on IIS:
In the Address: provide the service name, in the namespace "WCFServiceProxy" is used.
In the client program, user will enter for an emp id and click on “GetEmpDetails” button. Inside this button functionality, we are consuming the service and handling the fault messages:
- protected void btnSubmit_Click(object sender, EventArgs e)
- {
- try
- {
-
- WCFServiceProxy.ServiceClient serviceProxy = new ServiceClient();
- string strEmpId = txtEmpId.Text.Trim();
-
- WCFServiceProxy.Employee objEmp = serviceProxy.GetEmpDetails(strEmpId);
-
- List < Employee > employeeList = new List < Employee > ();
- employeeList.Add(objEmp);
-
- dgEmp.DataSource = employeeList;
- dgEmp.DataBind();
- } catch (FaultException < CustomFaultMsg > faultMsg)
- {
-
-
- string errmsg = faultMsg.Detail.MyCustomErrMsg;
- Response.Write("<Script> alert('" + errmsg + "')</script>");
- }
- }
In the client program Exception object should match with our customized Fault type.
Catch(FaultException<<Customized Fault Message >> FaultmessageObject)
The detail object inside the "FaultmessageObject" contains our customized fault message object. So we used "faultMsg.Detail.MyCustomErrMsg" to get our original customized fault message.
On successful search , the WCF service returns an emp object . This object is added to employee list and displayed to the user in a data grid.
On an unsuccessful search it throws the customized fault message staying that "The emp does not exist". This SOAP fault is handled and an alert message is displayed.
Using the try catch block at WCF service and throwing the SOAP faults to the client
In the above sample program , emp id is an int type. Now search for an employee id "sa". It throws an exception ,"input string was not in valid format". But in our program, we are not handling these exception.
In other words, at the service side, if there is any unhandled exception is occurred then those exception details are unavailable at the client side. Due to this, at the client side the following generic error message is displayed. This error message doesn't contain any underlying error/exception details.
In the following code snippet, we are using the try catch blocks at the server side and throw original Exception details to the client.
To throw the General Exception, first attach the Fault Contract to the service method.
- [OperationContract]
- [FaultContract(typeof(CustomFaultMsg))]
- [FaultContract(typeof(Exception))]
- public Employee GetEmpDetails(string EmpId)
- {
- try
- {
-
-
- var empRecord = from dr in ds.Tables[0].AsEnumerable()
-
-
-
- return objEmp;
- }
- }
-
- catch (FaultException < CustomFaultMsg > custmEx)
- {
-
- throw new FaultException < CustomFaultMsg > (custmEx.Detail, "This is from customized Exception block");
- }
-
- catch (Exception ex)
- {
-
- Exception GenEx = new Exception(ex.Message);
-
- throw new FaultException < Exception > (GenEx, "This is from Exception block");
- }
- }
Listing 3: Server Side Code
In this new code main changes are at exception blocks. Catch(Exception ex) is used to handle the all other exceptions.
At the client Side:
Now we have to handle the General Exception SOAP fault also.
- protected void btnSubmit_Click(object sender, EventArgs e)
- {
- try
- {
-
- WCFServiceProxy.ServiceClient serviceProxy = new ServiceClient();
- string strEmpId = txtEmpId.Text.Trim();
-
- WCFServiceProxy.Employee objEmp = serviceProxy.GetEmpDetails(strEmpId);
-
- List < Employee > employeeList = new List < Employee > ();
- employeeList.Add(objEmp);
-
- dgEmp.DataSource = employeeList;
- dgEmp.DataBind();
- } catch (FaultException < CustomFaultMsg > faultMsg)
- {
-
-
- string errmsg = faultMsg.Detail.MyCustomErrMsg;
- Response.Write("<Script> alert('" + errmsg + "')</script>");
- } catch (FaultException < Exception > GenEx)
- {
- string errmsg = GenEx.Detail.Message;
- Response.Write("<Script> alert('" + errmsg + "')</script>");
- } catch (Exception ex)
-
- {
- string errmsg = ex.Message;
- Response.Write("<Script> alert('" + errmsg + "')</script>");
- }
- }
Listing 4: Client Program
In this client program two new exception blocks are added.
catch (FaultException<Exception> GenEx)
Catch the general Exception raised by the WCF Service (not by the client program.)
catch (Exception ex)
This is a standard catch block which is used to catch the exception raised in the client program.
Now it displays the original error message details occurred at WCF Service program. Sample project code is attached.