6

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」タイプの最初の例外が発生します。

私は何か間違ったことをしていますか?どうすればこれを修正できますか?

ティア

4

2 に答える 2

5

解決策は、単純なロガー ファサードを作成して、Ninject をアプリの残りの部分から完全に切り離すことです。手順は次のとおりです。

1) Ninject の ILogger インターフェイスをコピーしてアプリの名前空間に貼り付けます (Ninject の ILogger を介して公開される型のために、Ninject のアセンブリに依存するだけでは継承しないでください)。

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 に依存します。それはそれについてです。

于 2011-08-30T10:59:26.560 に答える
0

公式の issue trackerによると、これは Ninject.Extensions.Logging のバージョン 3.0.2 で修正されているため、そのライブラリを更新すると問題が解決します。

于 2016-09-08T22:59:11.773 に答える