web-dev-qa-db-ja.com

静的ロガー、静的ヘルパークラスによる依存性注入

静的なLoggerクラスを呼び出す静的なクラスがあります。

例えば

static class DoesStuffStatic
{
  public static void DoStuff()
  {
    try
    {
      //something
    }
    catch(Exception e)
    {
      //do stuff; 
      Logger.Log(e);
    }
  }
}

static class Logger
{
  public static void Log(Exception e)
  {
     //do stuff here
  }
}

ロガーを静的クラスに挿入するにはどうすればよいですか?

注:私は 例を含む.NETでの依存性注入? を読みましたが、これはインスタンスロガーを使用しているようです。

29
geejay

静的ロガーを挿入することはできません。これをインスタンスロガーに変更する(可能な場合)か、インスタンスロガーでラップする(静的を呼び出す)必要があります。また、静的クラスに何かを注入することはかなり困難です(静的コンストラクタを制御しないため)。そのため、注入するすべてのオブジェクトをパラメーターとして渡します。

34
Grzenio

これは必ずしもそうではありません。静的ロガーが次のメソッドを公開している限り:

  • 注入したいクラスの注入、または
  • DIコンテナーを実行する前に適切なメソッド呼び出し(たとえば、asp.net global.asax Application_Startメソッドのようなもの)で注入すると、問題ありません。

ここに例があります。 DIには次のクラスを使用します。

 public class Logger : ILogger
    {
        public void Log(string stringToLog)
        {
           Console.WriteLine(stringToLog);
        }
    }

    public interface ILogger
    {
        void Log(string stringToLog);
    }

そして、ここにロガーを必要とする静的クラスがあります:

public static class SomeStaticClass
    {
        private static IKernel _diContainer;
        private static ILogger _logger;

        public static void Init(IKernel dIcontainer)
        {
            _diContainer = dIcontainer;
            _logger = _diContainer.Get<ILogger>();
        }


        public static void Log(string stringToLog)
        {
            _logger.Log(stringToLog);
        }


    }

これで、アプリのグローバルスタートアップ(この場合はmy global.asax.cs)で、DIコンテナーをインスタンス化して、静的クラスに渡すことができます。

public class Global : Ninject.Web.NinjectHttpApplication
    {

        protected override IKernel CreateKernel()
        {
            return Container;
        }


        static IKernel Container
        {
            get
            {
                var standardKernel = new StandardKernel();
                standardKernel.Bind<ILogger>().To<Logger>();
                return standardKernel;
            }

        }

        void Application_Start(object sender, EventArgs e)
        {
            SomeStaticClass.Init(Container);
            SomeStaticClass.Log("Dependency Injection with Statics is totally possible");

        }

そしてプレスト!これで、静的クラスでDIを使用できるようになりました。

それが誰かを助けることを願っています。多くの静的クラスを使用するアプリケーションを作り直しているところですが、しばらくの間、これをうまく利用しています。

29
Chris Smith

これは、静的ロガーの機能を「注入」する非常に簡単な方法です。

public static class Logger
{
    private static Action<string, Exception> _logError;
    public static bool Initialised;

    public static void InitLogger(Action<string, Exception, bool> logError)
    {
        if(logError == null) return;
        _logError = logError
        Initialised = true;
    }

    public static void LogError(string msg, Exception e = null)
    {
        if (_logError != null)
        {
            try
            {
                _logError.Invoke(msg, e);
            }
            catch (Exception){}
        }
        else
        {
            Debug.WriteLine($"LogError() Msg: {msg} Exception: {e}");
        }
    }
}

public class MainViewModel
{
    public MainViewModel()
    {
        //Inject the logger so we can call it globally from anywhere in the project
        Logger.InitLogger(LogError);
    }
    public void LogError(string msg, Exception e = null)
    {
        //Implementation of logger
    }
}
1
rolls

ロガーがどのように動作するかはわかりませんが、通常はRequestServiceを使用してインスタンスを取得できます。たとえば、抽象クラスでは:

this.HttpContext.RequestServices.GetService(typeof(YOUR_SERVICE));

HttpContextにアクセスできるコントローラーの場合は可能です。

2番目の方法は、たとえばStartupで使用する方法で、これを行うことができます。

serviceCollection.AddScoped(typeof(ICmsDataContext), typeof(TDbContext));

ここで、serviceCollectionは、dotnet CoreではIServiceCollectionです。

お役に立てば幸いです。

0
Petr Tomášek