使用Ninject填充Log4Net依赖关系

Bro*_*ook 25 c# log4net ninject

我在我的应用程序中使用Ninject作为DI容器.为了松散地耦合到我的日志库,我使用这样的接口:

public interface ILogger
    {
        void Debug(string message);
        void Debug(string message, Exception exception);
        void Debug(Exception exception);

        void Info(string message);
        ...you get the idea
Run Code Online (Sandbox Code Playgroud)

我的实现看起来像这样

public class Log4NetLogger : ILogger
    {
        private ILog _log;

        public Log4NetLogger(ILog log)
        {
            _log = log;
        }

        public void Debug(string message)
        {
            _log.Debug(message);
        }
        ... etc etc
Run Code Online (Sandbox Code Playgroud)

具有日志记录依赖性的示例类

public partial class HomeController
    {
        private ILogger _logger;

        public HomeController(ILogger logger)
        {
            _logger = logger;
        }
Run Code Online (Sandbox Code Playgroud)

在实例化Log4Net的实例时,您应该为其指定要记录的类的名称.这对Ninject来说是一个挑战.

目标是在实例化HomeController时,Ninject应该使用"HomeController"的"名称"实例化ILog

这是我的配置

public class LoggingModule : NinjectModule
    {
        public override void Load()
        {
            Bind<ILog>().ToMethod(x => LogManager.GetLogger(GetParentTypeName(x)))
                .InSingletonScope();

            Bind<ILogger>().To<Log4NetLogger>()
                .InSingletonScope();
        }

        private string GetParentTypeName(IContext context)
        {
            return context.Request.ParentContext.Request.ParentContext.Request.Service.FullName;
        }
    }
Run Code Online (Sandbox Code Playgroud)

然而,传递给ILog的"名称"并不是我所期待的.我也无法弄清楚任何押韵或理由,有时是正确的,大部分时间都不是.我看到的名称是OTHER类的名称,它们也依赖于ILogger.

Rub*_*ink 27

我个人没有兴趣抽象掉我的记录器,所以我的实现模块log4net.dll直接引用,我的构造函数根据ILog需要请求.

要实现这一点,使用Ninject v3的单行注册在我的结尾处看起来像这样static void RegisterServices( IKernel kernel ):

        kernel.Bind<ILog>().ToMethod( context=> 
            LogManager.GetLogger( context.Request.Target.Member.ReflectedType ) );
        kernel.Get<LogCanary>();
    }

    class LogCanary
    {
        public LogCanary(ILog log)
        {
            log.Debug( "Debug Logging Canary message" );
            log.Info( "Logging Canary message" );
        }
    }
Run Code Online (Sandbox Code Playgroud)

为了便于诊断日志记录问题,我在开始时坚持以下内容来获取非DI驱动的消息:

public static class NinjectWebCommon
{
    public static void Start()
    {
        LogManager.GetLogger( typeof( NinjectWebCommon ) ).Info( "Start" );
Run Code Online (Sandbox Code Playgroud)

在启动应用程序时产生以下结果:

<datetime> INFO  MeApp.App_Start.NinjectWebCommon           - Start
<datetime> DEBUG MeApp.App_Start.NinjectWebCommon+LogCanary - Debug Logging Canary message
<datetime> INFO  MeApp.App_Start.NinjectWebCommon+LogCanary - Logging Canary message
Run Code Online (Sandbox Code Playgroud)

  • @ user1068352谢谢; 该死的,现在你让我想起了[假的援助模式(第三个故事)](http://thedailywtf.com/Articles/Are-You-Cool,-Man-and-More.aspx) (2认同)

Rem*_*oor 18

Ninject.Extension.Logging扩展已经提供了您自己实现的所有功能.包括对log4net,NLog和NLog2的支持.

https://github.com/ninject/ninject.extensions.logging


您还想将以下内容用作记录器类型:

context.Request.ParentRequest.ParentRequest.Target.Member.DeclaringType
Run Code Online (Sandbox Code Playgroud)

否则,您将获得服务类型的记录器而不是实现类型.

  • 唯一的缺点是,即使我只想要ILogger接口,我仍然需要引用该程序集(例如:模拟单元测试的依赖项).我猜它没有伤害任何东西.绝对值得一提的是,只需简单的nuget添加即可完成所有工作. (3认同)
  • 为什么它是`.ParentRequest`的两个级别? (3认同)

Bro*_*ook 10

范围ILogILogger需要是瞬态的,否则它将只重用它创建的第一个记录器.感谢@Meryln Morgan-Graham帮我找到了.


Bro*_*ass 8

Bind<ILog>().ToMethod(x => LogManager.GetLogger(GetParentTypeName(x)))
            .InSingletonScope();
Run Code Online (Sandbox Code Playgroud)

您当前在Singleton范围内绑定,因此只创建一个将使用创建的第一个记录器的记录器.而是使用InTransientScope()