Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/310.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用Ninject填充Log4Net依赖关系_C#_Log4net_Ninject - Fatal编程技术网

C# 使用Ninject填充Log4Net依赖关系

C# 使用Ninject填充Log4Net依赖关系,c#,log4net,ninject,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);

我在应用程序中使用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;
        }
    }
公共类日志模块:ninject模块
{
公共覆盖无效负载()
{
Bind().ToMethod(x=>LogManager.GetLogger(GetParentTypeName(x)))
.InSingletonScope();
将()绑定到()上
.InSingletonScope();
}
私有字符串GetParentTypeName(IContext上下文)
{
返回context.Request.ParentContext.Request.ParentContext.Request.Service.FullName;
}
}

然而,传递给ILog的“名称”并不是我所期望的。我也找不出任何押韵或理由,有时是对的,但大多数时候不是。我看到的名称是其他类的名称,这些类也依赖于ILogger。

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

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

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

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


您还希望使用以下作为记录器类型:

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

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

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

为了实现这一点,在我的
静态void RegisterServices(IKernel内核)
的末尾,使用Ninject v3的单行注册如下所示:

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

<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
INFO MeApp.App_Start.NinjectWebCommon-Start
DEBUG MeApp.App_Start.NinjectWebCommon+LogCanary-调试日志记录Canary消息
INFO MeApp.App_Start.NinjectWebCommon+LogCanary-记录Canary消息

也许我的答案晚了,但我使用的是以下格式:

private static void RegisterServices(IKernel kernel)
    {
        kernel.Bind<ILog>()
            .ToMethod(c => LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType))
            .InSingletonScope();
    }
私有静态无效注册服务(IKernel内核)
{
kernel.Bind()
.ToMethod(c=>LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType))
.InSingletonScope();
}

我非常喜欢将Log4Net包装到我自己的接口中的想法。我不想依赖于Ninject的实现,因为对我来说,这只意味着我在整个应用程序中都依赖Ninject,我认为这与依赖注入的用途完全相反。与第三方服务分离。因此,我采用了最初的海报代码,但我更改了以下代码以使其正常工作

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

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

对于仍在寻找正确答案的所有人,正确的实现是:

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

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

当它不对的时候,它是什么样子的?你能模拟一个类关系,这样你就可以给一些假名字,至少解释一下你看到的名字之间的关系吗?或者只是复制一些代码?我看到的名称是依赖于
ILogger
的其他类的名称。例如,在我的
HomeController
中,它得到一个名为
SomethingRepository
的记录器。实际上,我想是你让我解决了这个问题。ILog/ILOGER的作用域不正确。它是为一个实例更新它们,然后重用它。他们应该是范围瞬态。这看起来很完美,我一定会检查!唯一的缺点是,即使我只想要ILogger接口(例如:模拟单元测试的依赖项),我仍然必须引用该程序集。我想这不会伤害任何东西。绝对值得这么做,因为我可以用一个简单的nuget add处理所有这些工作。为什么它有两个级别的
。ParentRequest
?我是唯一一个依赖IoC框架的人吗?我喜欢原始海报的想法。正如Remo所提到的,Ninject已经有一些组件可以完全满足您的需要,从您所展示的“GetParentTypeName”实现来看,Ninject扩展可能更健壮。@user1068352谢谢;该死,现在你提醒我,出于某种原因,我喜欢你的方法context.Request.Target对我来说是空的。希望我能得到这种方法working@JoshBerke猜测这是因为您正在执行一个测试请求(而不是像我的示例代码中那样间接地解析日志依赖关系)。您应该能够通过查看debugger@RubenBartelink这实际上是将ninject拉入一些没有根对象的遗留代码的副作用。我们使用的是服务定位器模式,所以目标就是请求它的人。一旦我将ninject配置为创建通用的asp.net处理程序,我们都很好。这正是我今天所使用的(这个问题现在已经有4年了),同样的原因是
    private string GetParentTypeName(IContext context)
    {
        var res = context.Request.ParentRequest.ParentRequest.Service.FullName;
        return res.ToString();
    }
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