Ninject.Extensions.Logging.Log4net意外行为

时间:2011-08-29 08:09:03

标签: c#-4.0 log4net ninject-2 nuget-package ninject-extensions

通过NuGet安装的Ninject(2.2.1.4)Extensions.Logging.Log4net(2.2.0.4)使用Log4Net(1.2.10)时遇到问题。

当我直接访问Log4Net时:

var logger = log4net.LogManager.GetLogger("Log4NetLoggerTest");
logger.Debug("foo { bar");

结果是:

2011-08-29 10:02:02,071 [9] DEBUG Log4NetLoggerTest foo { bar

但是,当通过Ninject访问记录器时:

using (IKernel kernel = new StandardKernel())
{
    var ninjectLogger = kernel.Get<NinjectLoggerTest>();
    ninjectLogger.Log.Debug("foo { bar");
}

NinjectLoggerTest就是这样:

using Ninject.Extensions.Logging;
namespace TestApp
{
    public class NinjectLoggerTest
    {
        public NinjectLoggerTest(ILogger log)
        {
            Log = log;
        }
        public ILogger Log;
    }
}

出乎意料的是,结果是:

2011-08-29 10:29:27,114 [10] DEBUG TestApp.NinjectLoggerTest <log4net.Error>Exception during StringFormat: Input string was not in a correct format. <format>foo { bar</format><args>{}</args></log4net.Error>

更糟糕的是,当使用ILogger的Trace方法时,mscorlib.dll中出现'System.FormatException'类型的第一次机会异常

我做错了吗?我该如何解决这个问题?

TIA

2 个答案:

答案 0 :(得分:5)

解决方案是创建一个简单的记录器外观,以完全将Ninject与应用程序的其余部分分离。步骤是:

1)将Ninject的ILogger接口复制/粘贴到应用程序的命名空间中(不仅仅是继承,或者你最终取决于Ninject的程序集,因为通过Ninject的ILogger公开了类型)。

2)创建自定义Logger,LoggerFactory和LoggerModule类。

3)将LoggerModule传递给Ninject的StandardKernel

为了完整性,代码为:

Ninject的ILogger - 复制/粘贴ILogger接口,将其命名空间更改为MyAppNamespace.Logger并添加以下方法:

void Debug(string message);
void Info(string message);
void Trace(string message);
void Warn(string message);
void Error(string message);
void Fatal(string message);

Logger.cs

namespace MyAppNamespace.Logger
{
    using System;
    class Logger : Ninject.Extensions.Logging.Log4net.Infrastructure.Log4NetLogger, ILogger
    {
        private const string DumpVerbatimFormat = "{0}";

        public Logger(Type type)
            : base(type)
        {
        }

        public void Debug(string message)
        {
            base.Debug(DumpVerbatimFormat, message);
        }

        public void Info(string message)
        {
            base.Info(DumpVerbatimFormat, message);
        }

        public void Trace(string message)
        {
            base.Trace(DumpVerbatimFormat, message);
        }

        public void Warn(string message)
        {
            base.Warn(DumpVerbatimFormat, message);
        }

        public void Error(string message)
        {
            base.Error(DumpVerbatimFormat, message);
        }

        public void Fatal(string message)
        {
            base.Fatal(DumpVerbatimFormat, message);
        }
    }
}

LoggerFactory.cs

namespace MyAppNamespace.Logger
{
    using System;
    using System.Collections.Generic;

    static class LoggerFactory
    {
        public static ILogger GetLogger(Ninject.Activation.IContext context)
        {
            return GetLogger(context.Request.Target == null ? typeof(ILogger) : context.Request.Target.Member.DeclaringType);
        }

        private static readonly Dictionary<Type, ILogger> TypeToLoggerMap = new Dictionary<Type, ILogger>();

        private static ILogger GetLogger(Type type)
        {
            lock (TypeToLoggerMap)
            {
                if (TypeToLoggerMap.ContainsKey(type))
                    return TypeToLoggerMap[type];

                ILogger logger = new Logger(type);
                TypeToLoggerMap.Add(type, logger);

                return logger;
            }
        }
    }
}

LoggerModule.cs

namespace MyAppNamespace.Logger
{
    public class LoggerModule : Ninject.Modules.NinjectModule
    {
        public override void Load()
        {
            log4net.Config.XmlConfigurator.Configure();
            Bind<ILogger>().ToMethod(LoggerFactory.GetLogger);
        }
    }
}

将这整个混乱放入一个单独的类库中,使其成为唯一依赖于Ninject的日志记录扩展和具体记录器的部分。您现在可以在整个应用程序中使用MyAppNamespace.ILogger,如下所示:

LoggerTest.cs

namespace MyAppNamespace.Whatever
{
    using Logger;
    public class LoggerTest
    {
        public LoggerTest(ILogger log)
        {
            Log.Info("Logger starting up");
        }
    }
}

在Main.cs中的某个地方

using (IKernel kernel = new StandardKernel(new Logger.LoggerModule()))
{
    kernel.Get<LoggerTest>();
}

Main取决于Ninject而不是日志记录扩展和你使用的任何记录器(代码适用于Log4Net,你需要为NLog调整一下)。该应用程序的其他部分依赖于MyAppNamespace.ILogger。就是这样。

答案 1 :(得分:0)

根据official issue tracker,这在Ninject.Extensions.Logging的3.0.2版本中得到修复,因此更新该库将解决问题。