【问题标题】:How to create a exception handling and logging class in C#如何在 C# 中创建异常处理和日志记录类
【发布时间】:2016-10-13 09:11:15
【问题描述】:

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

该层将位于用户界面和 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
}
}

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

已编辑:添加代码

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() 在当前上下文中不存在。

【问题讨论】:

    标签: c# .net exception-handling delegates n-tier-architecture


    【解决方案1】:

    对于这类事情,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&lt;T&gt;

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

    【讨论】:

    • 这与我的想法非常接近,我已经用最新的方法编辑了我的问题,但是关于方法有一个错误....看看
    • GetList() 是在另一个类中定义的,所以需要将ExceptionHandler.InitiateCall(() =&gt;GetList(screen) )); 改为return ExceptionHandler.InitiateCall(() =&gt; new DAL().GetList(screen));
    【解决方案2】:

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

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

    2. 范围日志记录(当您记录某些代码的开始/结束或时间)

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

       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
    }
    

    【讨论】:

    • 这不涉及异常处理。我认为问题是创建某种方法包装器来编写异常处理和异常记录,一次并将其用于许多方法。
    猜你喜欢
    • 1970-01-01
    • 2010-09-25
    • 2010-11-10
    • 1970-01-01
    • 2011-07-08
    • 1970-01-01
    • 2012-02-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多