使用Simple Injector注册NLog ILogger

时间:2016-01-06 21:53:12

标签: .net dependency-injection ioc-container nlog simple-injector

我有什么方法可以获取上下文,以便我可以检索loggerName并使用LogManager.GetLogger(loggerName)代替LogManager.GetCurrentClassLogger()吗?

我注意到container.RegisterConditional()可以访问上下文。

此外,我想暂时避免像SimpleLogging.NLog这样的解决方案。

最后,我愿意接受这不是正确的方法。顺便说一下,AOP是我已经探索过的一个选项(Is it a good practice to have logger as a singleton?)。

注意:我知道GetCurrentClassLogger()获取了我使用.NET反射检索的相同信息。

using NLog;
using SimpleInjector;

namespace DependencyInjection
{
    class Program
    {
        private static Container _container;
        static void Main(string[] args)
        {
            Bootstrap();
            _container.GetInstance<Greeter>().Greet();
        }

        private static void Bootstrap()
        {
            _container = new Container();

            _container.Register<ILogger>(() => LogManager.GetCurrentClassLogger(), Lifestyle.Transient);
            _container.Register<Greeter>();

            _container.Verify();
        }

        public class Greeter
        {
            private ILogger _logger;

            public Greeter(ILogger logger)
            {
                _logger = logger;
            }

            public void Greet()
            {
                _logger.Log(LogLevel.Info, "Hello world!");
            }
        }
    }
}

1 个答案:

答案 0 :(得分:13)

您需要定义一个代理记录器,将消息路由到正确的Nlog Logger。这个代理非常简单:

public class NLogProxy<T> : ILogger
{
    private static readonly NLog.ILogger logger = 
                 LogManager.GetLogger(typeof (T).FullName);

    void ILogger.Log(string message)
    {
        logger.Log(LogLevel.Info, message);
    }
}

您可以将此注册为

container.RegisterConditional(typeof(ILogger), 
     context => typeof(NLogProxy<>).MakeGenericType(context.Consumer.ImplementationType), 
     Lifestyle.Singleton, context => true);

您需要记录的所有地方都必须注入ILogger

至于AOP。我不确定你的意见是什么意思

  

必须维护的包装器(NLog.ILogger合同很大)。

记录为cross cutting concern,使用decorator是应用横切问题的好方法。使用装饰器,无法记录每个(私有)函数调用入口和出口,但为什么要这样?正如您可以阅读here,您可能不需要这样做。在大多数情况下,使用完整的堆栈跟踪记录服务被调用(传递给此服务的数据)和可能的异常的简单事实将是绰绰有余的。

所以考虑一下:

public interface ISomeService
{
    void DoSomething(string someParameter);
}

public class SomeServiceDecorator : ISomeService
{
    private readonly ISomeService decoratee;
    private readonly ILogger logger;

    public SomeServiceDecorator(ISomeService decoratee, ILogger logger)
    {
        this.decoratee = decoratee;
        this.logger = logger;
    }

    public void DoSomething(string someParameter)
    {
        try
        {
            this.logger.Log(string.Format("Do something called with {0}", someParameter));
            this.decoratee.DoSomething(someParameter);
        }
        catch (Exception e)
        {
            this.logger.Log(e.ToString());                
            throw;
        }
    }
}

此装饰器将使用传递给服务的信息记录所有函数调用,并记录任何异常。

但是这种方法会将类的数量增加2,所以不是DRY。引起此问题是因为此设计至少是次优的。围绕单个开放式通用抽象使用设计将完全解决此问题。您可以阅读此设计herehere

在这种情况下,您将拥有一个“LoggingDecorator”

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

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

    public void Handle(T command)
    {
        // serialize command to json and log
        this.logger.Log(serializedcommandData);
        this.decoratee.Handle(command);
    }
}

这个装饰器会记录你的所有命令。

这是我对AOP的看法......

相关问题