[英]How to create a exception handling and logging class in C#
我正在做一个小项目,我正在尝试创建一个处理异常和日志记录的层。
该层将位于用户界面和DAL之间,与BAL最为相似,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(在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
}
}
}
编辑:根据问题中添加的代码,您可以通过一些小的修改来解决有关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>
就个人而言,我认为应该以两种方式进行日志记录:
步骤记录(当您在代码中记录某些步骤时)
范围记录(当您记录某些代码的开始/结束或时间时)
因此,我总是选择使用以下两种方式创建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
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.