Centralize Exception Handling in WCF – Part 10

In this article we learn how we can implement centralize exception handling in wcf using IerrorHandler interface.
Before reading this article, I highly recommend reading my previous parts:
KnownType Attribute in WCF: Part 6
MessageContract in WCF: Part 7
Tracing in WCF: Part 8
Exception handling in WCF: Part 9
I am using same application which I worked in my previous article.
Let’s add a class in wcfService project and name it MyAppErrorHandler.cs and implement IErrorHandler interface. IErrorHandle interface is in System.ServiceModel.Dispatcher namespace.
IErrorHandler interface has two method.
1. HandleError : This method return type is bool. This method is called asynchronously after providefault method.
2. ProvideFault: This method return type is void. Whenever there is unhandled execption then this method is called automatically. In this function we are going to convert .net exception to SOAP fault exception.
Let’s understand the use of these function. For this I going to create table and stored procedure.
I am going to create a table “Exception_Master” and a procedure “USP_INSERTEXCEPTION” for saving the exception in database.

CREATE TABLE [dbo].[Exception_Master](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Message] [varchar](100) NULL,
[Type] [varchar](50) NULL,
[Source] [varchar](max) NULL,
[CreatedDate] [date] NULL
)

CREATE PROCEDURE [DBO].[USP_INSERTEXCEPTION]
(
@Message [varchar](100) = NULL,
@Type [varchar](50) = NULL,
@Source [varchar](max) = NULL
)
AS
BEGIN
INSERT INTO Exception_Master(Message,Type,Source) VALUES(@Message,@Type,@Source)
END

Now I am Implementing the IErrorHandle interface in MyAppErrorHandler class.
MyAppErrorHandler.cs

using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using System.Data;
using System.Data.SqlClient;

namespace wcfService
{
public class MyAppErrorHandler : IErrorHandler
{
SqlConnection con = new SqlConnection("Data Source=.;Initial Catalog=Goods;Integrated Security=True;");
public bool HandleError(Exception error)
{
string strSQL = string.Empty;
bool status = true;
con.Open();
try
{
con.Open();
SqlCommand cmd = new SqlCommand("USP_INSERTEXCEPTION",con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@Message", error.Message.ToString());
cmd.Parameters.AddWithValue("@Type", error.GetType().Name.ToString());
cmd.Parameters.AddWithValue("@Source", error.Source.ToString());
cmd.ExecuteNonQuery();
con.Close();
}
catch (Exception ex) {
status = false;
}
return status;
}

public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
if (error is FaultException)
return;

FaultException FE = new FaultException("This is test Fault Exception");
MessageFault MF = FE.CreateMessageFault();
fault = Message.CreateMessage(version, MF, null);
}
}
}

Let’s add one more class to our project and name it “ErrorHandlerAttribute” and now I am going to inherit this class from “Attribute” abstract class and implemeted by “IServiceBehavior” interface.

using System;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;

namespace wcfService
{
public class ErrorHandlerAttribute : Attribute,IServiceBehavior
{
private readonly Type errorHandler;
public ErrorHandlerAttribute(Type errorHandler)
{
this.errorHandler = errorHandler;
}
public void AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{

}

public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
{
IErrorHandler handler = (IErrorHandler)Activator.CreateInstance(this.errorHandler);
foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers)
{
ChannelDispatcher channelDispatcher = channelDispatcherBase as ChannelDispatcher;
if (channelDispatcher != null) {
channelDispatcher.ErrorHandlers.Add(handler);
}
}
}

public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
{

}
}
}

No need to providing any implementation of Validate and AddBindingParameters methods as of now.
Now I am going to decorate my “MathService” class with “ErrorHandlerAttribute”.
In MathService.svc.cs

using System;

namespace wcfService
{
[ErrorHandlerAttribute(typeof(MyAppErrorHandler))]
public class MathService : IMathService
{
public int AddTwoNo(int FirstNo, int Second)
{
return FirstNo + Second;
}

public int DivideTwoNo(int first, int second)
{
return first / second;
}
}
}

Let’s run the sql query and see the output.
no-record-found
Now run the application and see the output.You can make a breakpoint on ProvideFault and HandleError for checking that HandleError method works asynchronously or not.

While running the application it’s throw an error.

error

Press F5 and countinue to run the application and see the output.

output

Let’s run the sql query and see the output that error is saved in database or not.

sql-output

I hope you will enjoy this article.

Happy coding.

Tags: , , ,