2011-07-21 38 views
22

我在我的应用程序中使用Ninject作为DI容器。为了松散地耦合到我的日志库,我使用的界面是这样的:使用Ninject填充Log4Net依赖项

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。

+1

当这是不对的,这是什么样子?你可以模拟一个阶级关系,这样你就可以提供一些假名称,至少可以解释你所看到的名字之间的关系吗?或者只是复制一些你的代码? –

+0

我看到的名字是其他类的名字,它们依赖于'ILogger'。例如,在我的'HomeController'中,它得到一个名为'SomethingRepository'的记录器。 – Brook

+1

实际上,我想你只是让我解决它。 ILog/ILogger不在正确的范围内。这是一个新的例子,然后重新使用它。他们应该是有限的瞬态。 – Brook

回答

18

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

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


而且要使用以下内容作为记录器类型:

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

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

+0

看起来很完美,我一定会检查一下! – Brook

+2

唯一的缺点是,即使我只想使用ILogger接口(例如:模拟单元测试的依赖关系),仍然必须引用该程序集。我想这不会伤害任何东西。绝对值得,因为能够通过简单的nuget添加来处理所有这些工作,非常方便。 – Brook

+3

为什么它是两个级别的'.ParentRequest'? –

9

ILog和​​的范围需要是暂态的,否则它只会重用它创建的第一个记录器。感谢@Meryln Morgan-Graham帮助我找到。

+0

正如Remo提到的那样,Ninject已经有组件可以完成您想要的功能,并且通过显示的“GetParentTypeName”实现来判断,Ninject扩展可能更加健壮。 –

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

您当前正在辛格尔顿范围结合,因此只有一个记录器创建将使用创建的第一个名字。而是使用InTransientScope()

+1

我可以看到GetParentTypeName吗? – JDPeckham

24

我个人没有兴趣抽象掉我的记录器,所以我的实现模块直接引用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 
+0

+1,避免通过log4net正面! – user1068352

+2

@ user1068352谢谢;该死的,现在你已经提醒我了[假〜辅助模式(第三层)](http://thedailywtf.com/Articles/Are-You-Cool,-Man-and-More.aspx) –

+0

我喜欢你的方法由于某种原因context.Request.Target对我来说是空的.hope我得到这种方法工作 – JoshBerke

3

也许我的回答是迟,但我使用这种格式:

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

嗯。谨慎使用'InSingletonScope' - GetLogger参数的要点在于日志具有与日志条目相关的正确类型。也使用'MethodBase.GetCurrentMethod().DeclaringType'可能不总是可靠的 - 内联等可以影响确切的上下文是什么(与实际检查Ninject请求上下文'c') –

0

我喜欢在我自己的接口包裹log4net的的想法。我不想依赖于Ninject的实现,因为对我来说,这意味着我在整个应用程序中依赖于Ninject,我认为这与依赖注入的目的完全相反。与第三方服务脱钩。所以我拿了原来的海报代码,但我改变了下面的代码来使它工作。

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

我有打电话给ParentRequest.ParentRequest这样,当我打印布局%记录器将打印调用log4net的日志方法而不是log4net的类称为日志方法,该方法的类。

+0

这正是我正在使用的这个一天(这个问题现在已经快4岁了),出于你提到的同样的原因。 – Brook

+0

是的感谢代码!我逐字使用了它,我对它很满意。我只需要修复这个方法。我也无法理解为什么该方法调用ParentRequest.ParentRequest,所以我添加了我自己的答案,任何人使用Google搜索。 – mac10688

+0

Ninject文档是错误的,然后。 – regisbsb

3

对于所有的你,还在寻找正确的答案,正确的实施是:

public class LoggingModule : NinjectModule 
{ 
    public override void Load() 
    { 
     Bind<ILog>().ToMethod(x => LogManager.GetLogger(x.Request.Target.Member.DeclaringType)); 

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

重视:

x.Request.Target.Member.DeclaringType 
+0

我认为这应该被评为答案。这显示了如何执行绑定并且不要求您为ninject外观版本的ILogger(来自Ninject.Extensions.Logging)提供参考。将与任何记录器一起工作。 – Nicholi