web-dev-qa-db-ja.com

Ninjectを使用してLog4Netの依存関係を埋める

アプリケーションでDIコンテナとしてNinjectを使用しています。ロギングライブラリに疎結合するために、次のようなインターフェイスを使用します。

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に渡される「名前」は私が期待しているものではありません。韻や理由もわかりません。正しい場合もありますが、ほとんどの場合はそうではありません。私が見ている名前は、ILoggerにも依存している他のクラスの名前です。

25
Brook

Ninject.Extension.Logging拡張機能は、自分で実装しているすべてのものをすでに提供しています。 log4net、NLog、NLog2のサポートを含みます。

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


また、ロガータイプとして以下を使用する必要があります。

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

それ以外の場合は、実装タイプではなくサービスタイプのロガーを取得します。

18
Remo Gloor

私は個人的にロガーを抽象化することに興味がないので、実装モジュールは_log4net.dll_を直接参照し、コンストラクターは必要に応じてILogを要求します。

これを実現するために、Ninject v3を使用した1行の登録は、私の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
_
27
Ruben Bartelink

ILogILoggerのスコープは一時的である必要があります。そうでない場合、作成した最初のロガーを再利用するだけです。それを見つけるのを手伝ってくれた@ MerylnMorgan-Grahamに感謝します。

10
Brook
_Bind<ILog>().ToMethod(x => LogManager.GetLogger(GetParentTypeName(x)))
            .InSingletonScope();
_

現在、Singletonスコープでバインドしているため、最初に作成されたロガーの名前を使用するロガーが1つだけ作成されます。代わりにInTransientScope()を使用してください

8
BrokenGlass

まだ正しい答えを探しているすべての人にとって、正しい実装は次のとおりです。

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
4
regisbsb

多分私の答えは遅れていますが、私はこのフォーマットを使用しています:

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

Log4Netを自分のインターフェースでラップするというアイデアが好きです。 Ninjectsの実装に依存したくないのは、アプリケーション全体でNinjectに依存することを意味し、依存性注入の目的とは正反対だと思ったからです。サードパーティのサービスから切り離します。そこで、元のポスターコードを使用しましたが、次のコードを変更して機能させました。

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

ParentRequest.ParentRequestを呼び出す必要があります。これにより、レイアウト%loggerを出力すると、Logメソッドを呼び出したメソッドのLog4Netクラスではなく、Log4Netlogメソッドを呼び出すクラスが出力されます。

0
mac10688