使用Ninject填充Log4Net依赖关系

时间:2011-07-21 19:13:33

标签: 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

我的实现看起来像这样

public class Log4NetLogger : ILogger
    {
        private ILog _log;

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

        public void Debug(string message)
        {
            _log.Debug(message);
        }
        ... etc etc

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

public partial class HomeController
    {
        private ILogger _logger;

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

在实例化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;
        }
    }

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

6 个答案:

答案 0 :(得分: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" );
        }
    }

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

public static class NinjectWebCommon
{
    public static void Start()
    {
        LogManager.GetLogger( typeof( NinjectWebCommon ) ).Info( "Start" );

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

<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

答案 1 :(得分:18)

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

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


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

context.Request.ParentRequest.ParentRequest.Target.Member.DeclaringType

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

答案 2 :(得分:9)

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

答案 3 :(得分:7)

Bind<ILog>().ToMethod(x => LogManager.GetLogger(GetParentTypeName(x)))
            .InSingletonScope();

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

答案 4 :(得分:3)

也许我的答案很晚,但我使用的是这种格式:

private static void RegisterServices(IKernel kernel)
    {
        kernel.Bind<ILog>()
            .ToMethod(c => LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType))
            .InSingletonScope();
    }

答案 5 :(得分:0)

我喜欢在我自己的界面中包装Log4Net的想法。我不想依赖于Ninjects实现,因为对我而言,这意味着我在整个应用程序中依赖于Ninject,我认为这与依赖注入的完全相反。从第三方服务中解脱出来。所以我采用了原始的海报代码,但我更改了以下代码以使其正常工作。

    private string GetParentTypeName(IContext context)
    {
        var res = context.Request.ParentRequest.ParentRequest.Service.FullName;
        return res.ToString();
    }

我必须调用ParentRequest.ParentRequest,这样当我打印布局%logger时,它将打印调用Log4Net日志方法的类,而不是调用Log方法的方法的Log4Net类。