Tuesday, 9 February 2016

Write WCF Error details to Windows Event Log from client (Service Consumer)

Contents



  

1.2.SCOPE
WCF is one of the latest technologies of Microsoft that is used to build service-oriented applications. Based on the concept of message-based communication, in which an HTTP request is represented uniformly, WCF makes it possible to have a unified API irrespective of diverse transport mechanisms. WCF is mostly used in Windows platform systems, so logging error messages to windows event viewer will help the developer to easily identify the errors when it occurs.
WCF-Windows Communication Foundation

<This section should list all the applicable and reference documents>



Maintaining a log is one of the important aspects in programming. If we are maintaining the logs correctly, then we can simply identify if any errors are occurring in our program. Programmers are using many techniques to Maintain Logs. Some of the most commonly used techniques in C# is listed below
1) Creating a log file and maintaining the logs in that file.
2) Writes logs to Windows Event Log
3) log4net
Here we are looking for the second one Write Logs to Windows Event Log.
Step 1) Enable Fault Contract in WCF Application
Step 2) Get the error details from WFC to Client using Fault Contract 
Step 3) Write error details log to Windows Event Log
We can go step by step process.

First we need to get the error details from WCF in our client Application
See the below code which implement Fault Contract, using the help of below code
We can pass error details to client from WCF.

Ø  Create a sample WCF project
Ø  Create file ICalculatorService.cs
Ø  Create file Calculator.cs

Replace ICalculator.cs with following content.
    [ServiceContract]
    using System;
using System.Runtime.Serialization;
using System.ServiceModel;

namespace Calculator
{
    [ServiceContract]
   
    public interface ICalculatorService
    {
        [OperationContract]
        [FaultContract(typeof(ErrorDetails))]
        ResultSet PerformCalculatorOperations(int firstInput,int secondInput,string operationType);

    }

    [DataContract]
    public class ResultSet
    {
        [DataMember]
        public int Result { get; set; }
        [DataMember]
        public string Staus { get; set; }
    }
    public class ErrorDetails
    {
        public string  ErrorInfo { get; set; }

    }
}

Replace Calculator.cs file with following content.
using System;
using System.ServiceModel;

namespace Calculator
{
    public class CalculatorService : ICalculatorService
    {
        ResultSet result = new  ResultSet();
        ErrorDetails errorDetails = new ErrorDetails();
        public ResultSet PerformCalculatorOperations(int firstInput, int secondInput, string operationType)
        {
            try
            {
                switch (operationType)
                {
                    case "Addition":
                        Addition(firstInput, secondInput);
                        break;
                    case "Subtraction":
                        Subtraction(firstInput, secondInput);
                        break;
                    case "Multiplication":
                        Multiplication(firstInput, secondInput);
                        break;
                    case "Division":
                        Division(firstInput, secondInput);
                        break;
                    default:
                        result.Staus = "Error";
                        break;
                }
            }
            catch (Exception ex)
            {
              
                errorDetails.ErrorInfo = ex.ToString();
                throw new FaultException<ErrorDetails>(errorDetails, ex.ToString());
            }

            return result;

        }
        public void Addition(int firstInput, int secondInput)
        {
            result.Result = firstInput + secondInput;
            result.Staus = "Sucess";
        }
        public void Subtraction(int firstInput, int secondInput)
        {
            result.Result = firstInput - secondInput;
            result.Staus = "Sucess";
        }
        public void Multiplication(int firstInput, int secondInput)
        {
            result.Result = firstInput * secondInput;
            result.Staus = "Sucess";
        }
        public void Division(int firstInput, int secondInput)
        {
           
                result.Result = firstInput / secondInput;
          
            result.Staus = "Sucess";
        }

    }
}

Ø  Create A sample MVC Project for consuming WCF Service
Ø   Ddd above wcf service reference in newly created MVC Project.
Ø  Create a controller named CalculatorConsumer

Replace the content of CalculatorConsumerController with following code.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.ServiceModel;
using System.Web;
using System.Web.Mvc;

namespace CalculatorConsumer.Controllers
{
    public class CalculatorConsumerController : Controller
    {
        // GET: CalculatorConsumer
        public ActionResult Index()
        {

            Calculator.CalculatorServiceClient consumer = new Calculator.CalculatorServiceClient();
            try
            {
                var consumerResult = consumer.PerformCalculatorOperations(11, 0, "Division");
            }
            catch (FaultException<Calculator.ErrorDetails> errorDetails)
            {
                string ErrorDetails = errorDetails.Detail.ErrorInfo;
                // Create an EventLog instance and assign its source.
                EventLog eventLog = new EventLog();
                eventLog.Source = "FromWCF";
                // Create the source and log, if it does not already exist.
                if (!EventLog.SourceExists("WCF"))
                {
                    EventLog.CreateEventSource("WCF", "WCFLog");
                }
                // Write an entry in the event log.               
                eventLog.WriteEntry(ErrorDetails, EventLogEntryType.Warning, 1001);



            }

            return View();
        }
    }
}

Now you can check your Windows Event Log.
Control Panel->Administrative Tools->Event Viewer->Windows Logs->Application

Then if you are clicking the Particular log then you can see the details and general information like below.





Fault Contract - Handling Errors in WCF


Error Handling :

Whenever  we  writes a computer program we must curious about the Unexpected Exceptions.
An exception can  stops our entire program or may be it can cause performance degradation . So handling the exceptions are very important. In asp.net we have lot of exception handling mechanisms. But WCF is not that much straight forward.
The main problem is WCF is a service which is apart from our client so if any Exceptions are occurred in WCF code then we cannot able to find that through normal Exception handling in client side , if any error happens in our program then normally we need to propagate a user-friendly error message to the client, who consumes the WCF Service. For handling exceptions in WCF we are using Exception handling mechanism called Fault Contract
  
What is Fault Contract  ???

Fault Contract  is an exception handling mechanism which will help us to pass WCF Service errors/Exceptions to the client (Service consumer). In other words Fault Contract is mechanism to communicate error information between server and client
We can go through a simple example that demonstrate the use of Fault Contract .

Think in our WCF  Service Library we have a method like below
IService.cs

    [ServiceContract]
    public interface IService1
    {
       

        [OperationContract]
        int Divide(int Number1, int Number2);
    }
[DataContract]
    public class DivideClass
    {
        [DataMember]
        public  bool Result { get; set; }
        [DataMember]
        public  string ErrorMessage { get; set; }
        [DataMember]
        public  string ErrorDetails { get; set; }

    }
Service.cs
      public int Divide(int Number1,int Number2)
        {
            DivideClass objdiv = new DivideClass();
           
                int Result = Number1 / Number2;
                return Result;
           
        }
And we are try to use this service from a client like below
try
            {
                ExampleService.Service1Client obj = new ExampleService.Service1Client();
               
                int Result = obj.Divide(10, 0);
                            }
            catch (Exception e)
            {
           }
In the above code we are passing two variables 10,0 to the service and our service will divide the first number with second. Our second number is 0 so there should be a divided by zero exception. But we are using this service from a client so we don't have any idea about what is happening in WCF code, we don't have any information about the error and all. How can we get the error details from WCF??? for that purpose we are using Fault Contract.
See the below code
IService.cs

    [ServiceContract]
    public interface IService1
    {
       
        //Fault Contract Handling
        [OperationContract]
        [FaultContract(typeof(DivideClass))]
        int Divide(int Number1, int Number2);
    }

Service.cs
public int Divide(int Number1,int Number2)
        {
            DivideClass objdiv = new DivideClass();
            try
            {
                int Result = Number1 / Number2;
                return Result;
            }
            catch (Exception ex)
            {
                objdiv.Result = false;
                objdiv.ErrorMessage = "error occurred. Please try later.";
                objdiv.ErrorDetails = ex.ToString();
                throw new FaultException<DivideClass>(objdiv, ex.ToString());
            }
        }

In our Client Side
try
            {
               
                ExampleService.Service1Client obj = new ExampleService.Service1Client();
               
                int Result = obj.Divide(10, 0);
                            }
            catch (FaultException<ExampleService.DivideClass> Fex)
            {
                string ErrorDetails = Fex.Detail.ErrorMessage + "ErrorDetails::" +                Fex.Detail.ErrorDetails;
               
            }

Using the above method we can simply pass the error from WCF Service to our client (Service Consumer)