如何在 C# 中创建异常处理和日志记录 class

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

我正在做一个小项目,我正在尝试创建一个层来处理异常和日志记录。

该层将位于用户界面和 DAL 之间,主要类似于 BAL,后者将具有一些通用方法,然后启动对数据访问层的进一步调用。

类似这样的事情

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
}
}

该层将充当处理和记录异常的中心存储库。我无法创建我描述的方法,专家能否提供一些片段来展示这种情况。

已编辑:添加了代码

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();
        }
    } 

它给出错误 GetList() 在当前上下文中不存在。

对于这类事情,AOP(面向方面​​的编程,请参阅 https://en.wikipedia.org/wiki/Aspect-oriented_programming)非常适合。

这些是横切关注点,如果处理不当会使代码混乱。

请参阅示例 AOP 框架 PostSharp。即使使用易于编码的免费版本。也有(可能是付费的)内置方面,比如 http://doc.postsharp.net/exception-tracing.

一个简单的替代方法是使用 Func 或 Action(在控制台应用程序中尝试):

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
        }
    }
}

编辑: 根据您在问题中添加的代码,您可以通过一些小的修改来解决有关 GetList() 的错误:

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();
    }
}

根据提供的代码,您不需要 InitiateCall 中的 object[] parms 参数。 Func<T>

中给出了方法调用所需的任何参数

我个人认为应该通过两种方式进行日志记录:

  1. 步骤记录(当您在代码中记录某些步骤时)

  2. 范围日志记录(当您记录 begin/end 某些代码或时间)

所以,我总是选择用这两种方式创建 ILogger class:

   public sealed class Logger : ILogger
    {
        private readonly Serilog.ILogger _seriLogger;

        public Logger(Serilog.ILogger seriLogger)
        {
            _seriLogger = seriLogger;
        }

        public void Debug(string format, params object[] args)
        {
            _seriLogger.Debug(format, args);
        }

        public void Info(string format, params object[] args)
        {
            _seriLogger.Information(format, args);
        }

        public void Warn(string format, params object[] args)
        {
            _seriLogger.Warning(format, args);
        }

        public void Error(Exception e, string format, params object[] args)
        {
            _seriLogger.Error(e, format, args);
        }

        public void Fatal(Exception e, string format, params object[] args)
        {
            _seriLogger.Fatal(e, format, args);
        }

        public IDisposable GetScope(string name, long timeout = 0)
        {
            return new LoggerScope(this, name, timeout);
        }
    }

    internal class LoggerScope : IDisposable
    {
        private readonly ILogger _logger;

        private readonly string _name;

        private readonly long _timeout;

        private readonly Stopwatch _sw;

        private bool ExceedScope
        {
            get { return _timeout > 0; }
        }

        public LoggerScope(ILogger logger, string name, long timeout)
        {
            _logger = logger;
            _name = name;
            _timeout = timeout;

            if (!ExceedScope)
            {
                _logger.Debug("Start execution of {0}.", name);
            }
            _sw = Stopwatch.StartNew();
        }

        public void Dispose()
        {
            _sw.Stop();

            if (ExceedScope)
            {
                if (_sw.ElapsedMilliseconds >= (long)_timeout)
                {
                    _logger.Debug("Exceeded execution of {0}. Expected: {1}ms; Actual: {2}ms.", _name, _timeout.ToString("N"), _sw.Elapsed.TotalMilliseconds.ToString("N"));
                }
            }
            else
            {
                _logger.Debug("Finish execution of {0}. Elapsed: {1}ms", _name, _sw.Elapsed.TotalMilliseconds.ToString("N"));
            }
        }
    }

然后,如果我想记录一些东西,我会像这样使用它,没有 AOP:

using(_log.GetScope("Some describable name"))
{
   //Some code here
}