There are several ways to implement Global Exception Handling in WCF, for example using an IErrorHandler (the best way to handle the uncaught exceptions) or by creating your own Façade for calling all service methods. In this article, we'll discuss an Interceptor IOperationInvoker that can be used before and after activity when service actually calls its operations. There are several things you can perform at this stage, like Logging, Tracing or handling the exception (especially Unhandled Exceptions).
First we'll start to look at a high level of the picture where the operation invoker actually stands when a client makes a service method call. The following diagram shows a picture of that.
So let's create a WCF service project. (Learn how to create and consume a WCF service.) After adding the project, we need to add some operation in the service so for example our service operation is GetParseData(). So it can look something like this, as generated from the project template.
IServiceContract
Service.cs
To get some exceptions we'll use custom logic in the Implementation of GetParseData(). So it can look something like this.
Here in this method we have introduced some known and unhandled exceptions. To demonstrate the logging and Global Exception Handling we'll now create a class that will Implement the IOperationInvoker interface.
In this implementation of IOperationInvoker we will only focus on the Invoke() method to log the request begin and request end. Also a Try Catch block is placed on the invoke statement so that we can capture any unhandled exception and log it in the first place with all details. And we're not sending the complete exception to the client but a custom FaultException with less details or a message.
- [OperationContract]
- string GetParseData(string value)
- public string GetParseData(string value)
- {
- return string.Format("You entered: {0}", value);
- }
- public string GetParseData(string value)
- {
- // check if value is alphabets/Numeric
- if (string.IsNullOrEmpty(value))
- {
- throw new ArgumentException("Method parameter value can not be null or empty");
- }
- // split the value if it contains spaces and return first two words
- var stringArray = value.Split(' ');
- // This will/may cause an Unhandled exception for OutOfIndex in case of single word is passed.
- return string.Format("{0}_{1}_{2} ..", stringArray[0], stringArray[1], stringArray[2]);
- }
- /// <summary>
- /// Global error handler of service operations using IOperationInvoker
- /// </summary>
- public class ErrorHandlingLoggingOperationInvoker : IOperationInvoker
- {
- private readonly ILog logger;
- private IOperationInvoker invoker;
- private string operationName;
- public ErrorHandlingLoggingOperationInvoker(IOperationInvoker baseInvoker, DispatchOperation operation)
- {
- this.invoker = baseInvoker;
- this.operationName = operation.Name;
- XmlConfigurator.Configure();
- logger = LogManager.GetLogger("serviceLogger");
- }
- public bool IsSynchronous
- {
- get
- {
- return true;
- }
- }
- public object[] AllocateInputs()
- {
- return this.invoker.AllocateInputs();
- }
- //This is our intent method to intercept the request.
- public object Invoke(object instance, object[] inputs, out object[] outputs)
- {
- logger.InfoFormat("Start command operation:{0}", this.operationName);
- object result = null;
- try
- {
- result = this.invoker.Invoke(instance, inputs, out outputs);
- }
- catch (Exception exception)
- {
- logger.Error("Unhandled Exception: ", exception);
- outputs = new object[] { };
- throw new FaultException(new FaultReason(exception.Message));
- }
- logger.InfoFormat("End command operation:{0}", this.operationName);
- return result;
- }
- public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
- {
- throw new Exception("The operation invoker is not asynchronous.");
- }
- public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
- {
- throw new Exception("The operation invoker is not asynchronous.");
- }
- }

MarcoPosted Sep 16, 2021, 8:33 PM
Hi, how to get logger instance used inside operation invoker in service operation? I need to use Serilog via Microsoft.Extensions.Logging.Ilogger with BeginScope to mark each log with operation ID, to do this i need same log instance created inside operation invoker.