如何在c#中创建异常处理和日志类
本文关键字:异常处理 日志 创建 | 更新日期: 2023-09-27 18:12:56
我正在做一个小项目,我正在尝试创建一个处理异常和日志的层。
这一层将位于用户界面和数据访问层之间,就像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>
我个人认为日志记录应该以两种方式完成:
步骤日志(当你在代码中记录一些步骤时)
范围日志(当你记录一些代码的开始/结束或时间)
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
}