Search code examples
c#.netexceptiondelegatesn-tier-architecture

How to create a exception handling and logging class in C#


I am working on a small project, I am trying to create a layer that will handle exception and logging.

This layer will sit in between User interface and DAL, mostly like BAL which will have some generic method that will then initiate further call to Data access layer.

Some thing like this

Public Class ExceptionHandler
{
//which should take a method name,parameters and return a object.
Public T InitiateDatabaseCall(//method name as input,parameters)
{
try
{
//then make the call to the method using the input parameter and pass the parameters
}
catch(Exception e)
{
// do logging
}
}

This layer will act as center repository to handle and log exception. I am not able to create the method that i described can experts provide some snippet that will show case this scenario.

Edited: With code added

static void Main(string[] args)
        {

            BAL b = new BAL();
            var ll = b.GetFieldList("xxxxyyyy");

        }





    public class BAL
    {
        public List<Fields> GetFieldList(string screen)
        {
            if(!string.IsNullOrEmpty(screen))
            {
                ExceptionHandler.InitiateCall(() =>GetList(screen) ));
            }
        }

    }


    public static class ExceptionHandler
    {
        public T InitiateCall<T>(Func<T>method,object[] parms) where T : object 
        {
            try
            {
                return method.Invoke();
            }
            catch(Exception ex)
            {
                return default(T);
            }
        }
    }

    public class DAL
    {

        public  List<Fields> GetList(string name)
        {
            VipreDBDevEntities context = new VipreDBDevEntities();
            return context.Database.SqlQuery<Fields>("SCREEN_FIELDS_SELECT @SCREEN_NAME", name).ToList();
        }
    } 

It gives error GetList() does not exist in current context.


Solution

  • For these kind of things AOP (Aspect Oriented Programming, see https://en.wikipedia.org/wiki/Aspect-oriented_programming) is a really good fit.

    These are cross-cutting concerns that are cluttering code if not done properly.

    See for an example AOP framework PostSharp. Even with the free version that is simple to code. There are also (might be paid) build-in aspects for that, like http://doc.postsharp.net/exception-tracing.

    A simple alternative is using a Func or Action (try it out in a Console App):

    static void Main(string[] args)
    {
        ExceptionHandler.InitiateDatabaseCall(() => CallDb("Dummy"));
        ExceptionHandler.InitiateDatabaseCall<int>(() => { throw new InvalidOperationException(); });
    }
    
    int CallDb(string justToShowExampleWithParameters)
    {
        return 5;   
    }
    
    public static class ExceptionHandler
    {
        public static T InitiateDatabaseCall<T>(Func<T> method)
        {
            try
            {
                return method.Invoke();
            }
            catch (Exception e)
            {
                // do logging
                Console.WriteLine(e.Message);
                return default(T); // or `throw` to pass the exception to the caller
            }
        }
    }
    

    Edit: based on your added code in the question you can solve the error about GetList() by some minor modifications:

    static void Main(string[] args)    {
        BAL b = new BAL();
        var ll = b.GetFieldList("xxxxyyyy");
    }
    
    public class BAL
    {
        public List<Fields> GetFieldList(string screen)
        {
            if (!string.IsNullOrEmpty(screen))
            {
                return ExceptionHandler.InitiateCall(() => new DAL().GetList(screen)); // Slight modification of your code here
            }
            else
            {
                return null; // or whatever fits your needs
            }
        }
    }
    
    public class ExceptionHandler
    {
        public static T InitiateCall<T>(Func<T> method) 
        {
            try
            {
                return method.Invoke();
            }
            catch (Exception ex)
            {
                //log
                return default(T);
            }
        }
    }
    
    public class DAL
    {
        public  List<Fields> GetList(string name)
        {
            VipreDBDevEntities context = new VipreDBDevEntities();
            return context.Database.SqlQuery<Fields>("SCREEN_FIELDS_SELECT @SCREEN_NAME", name).ToList();
        }
    }
    

    You don't need the object[] parms parameter in InitiateCall given the provided code. Any paramaters you need for the method call are given in the Func<T>