使用Simple Injector注册NLog ILogger

Gon*_*nto 12 .net dependency-injection nlog ioc-container simple-injector

有什么方法可以获得上下文所以我可以检索loggerName并使用LogManager.GetLogger(loggerName)而不是LogManager.GetCurrentClassLogger()

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

另外,我现在想避免像SimpleLogging.NLog这样的解决方案.

最后,我愿意接受这不是正确的方法.顺便说一下,AOP是我已经探索过的一个选项(将记录器作为单身人员是一种很好的做法吗?).

注意:我知道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!");
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Ric*_*Net 14

您需要定义一个代理记录器,它将消息路由到正确的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);
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以将此注册为

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

你需要记录的任何地方你都必须注射ILogger.

至于AOP.我不确定你的评论是什么意思

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

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

所以考虑一下:

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

在这种情况下,你将有一个`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);
    }
}
Run Code Online (Sandbox Code Playgroud)

而这个装饰器将记录您的所有命令.

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