穷人使用IDisposable进行面向方面的编程和日志记录

时间:2013-01-30 14:25:47

标签: logging reflection automation aop idisposable

我的项目中使用任何外部资源(数据库,Web服务调用等)的每个方法都必须进行日志记录。问题是我最终得到了很多重复的代码。句子看起来是一样的,但是它们的参数会改变(即方法名称)。

这似乎是重构我的代码的一个非常好的观点。除了AOP库,我想知道我至少可以避免使用魔术字符串并编写一个一次性对象并将方法体包装在一个using语句中,如下所示:

public void LoggedMethod(int param)
{
    using (new AutoLog())
    {
        // do whatever needs to be done
    }
}

我的AutoLog类是一次性的,可以在实例化和处理时写一个日志调用。我知道我可能会(ab)使用StackTrace类,但AFAIK这会大大减慢我的方法,因为这个特殊类很慢。

我的日志条目应该是(所有这些条目当然都包含方法名称):

  • 方法调用的开始
  • 方法调用结束
  • (可选)方法参数 - 当然是序列化的(JSON?)
  • (可选)执行时间

问题

我应该如何实现AutoLog课程以尽快开展工作?如果我还可以读取方法参数,那就更好了,所以我可以将它们序列化并记录它们。

1 个答案:

答案 0 :(得分:1)

  

我的项目中使用任何外部资源(数据库,Web服务调用等)的每个方法都必须进行日志记录

我简直不敢相信。你可能是logging too much

  

句子看起来是一样的,但是它们的参数会改变(即方法名称)。

在这种情况下,您可能会错过代码中的一些常规抽象。根据我的经验,你应该:

对与架构密切相关的代码有一般抽象。

请查看this article about command handlers和本文关于repositories and custom queries的文章。这两篇文章都围绕架构概念定义了一个通用接口。 (你应该至少阅读第一篇文章,其余的答案才有意义。)

使用通用接口,可以很容易地用装饰器包装一整套相关操作。例如,这个装饰器可以包含在执行用例的所有操作中:

public class LoggingCommandHandlerDecorator<TCommand>
    : ICommandHandler<TCommand>
{
    private readonly ICommandHandler<TCommand> decoratee;
    private readonly ILogger logger;

    public LoggingCommandHandlerDecorator(
        ICommandHandler<TCommand> decoratee,
        ILogger logger)
    {
        this.decoratee = decoratee;
        this.logger = logger;
    }

    void ICommandHandler<TCommand>.Handle(TCommand command)
    {
        using (new AutoLog())
        {
            this.decoratee.Handle(command);
        }
    }
}
  

我应该如何实现我的AutoLog类以尽可能快地工作?

你知道吗,装饰器只是一个薄的包装器,几乎没有开销。使用这种方法,您通常拥有的所有方法参数现在都包含在一个对象中。这对于日志记录非常方便,因为您只需将整个TCommand序列化为XML,JSon或更易读的格式,您只需编写一次此代码即可。

由于你担心性能,因为这个LoggingCommandHandlerDecorator<TCommand>是泛型类型,你可以做的是为该类型添加一个静态构造函数(静态构造函数每个闭合的通用版本运行一次)和预编译一些代码,允许您有效地序列化该命令消息。绝对没有任何东西可以与之竞争。甚至AOP框架在访问方法的参数时也使用反射和构建带有装箱的动态数组。

请注意,应用像这样的装饰器没有“穷人”。但是,当您的架构不遵循SOLID原则时,当您尝试此操作时,您很快就会遇到麻烦。这些原则是获得灵活和可维护软件的关键。