web-dev-qa-db-fra.com

Injection de dépendance avec un logger statique, classe d'assistance statique

J'ai une classe statique qui appelle une classe statique Logger,

par exemple

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
  }
}

Comment puis-je injecter le logger dans ma classe statique?

Remarque: J'ai lu Dependency Injection in .NET avec des exemples? , mais cela semble utiliser un enregistreur d'instance.

24
geejay

Vous ne pouvez pas injecter un enregistreur statique. Vous devez soit le changer en un enregistreur d'instance (si vous le pouvez), soit l'envelopper dans un enregistreur d'instance (qui appellera le statique). De plus, il est assez difficile d'injecter quoi que ce soit dans une classe statique (car vous ne contrôlez en aucun cas le constructeur statique) - c'est pourquoi j'ai tendance à passer tous les objets que je veux injecter en tant que paramètres.

30
Grzenio

Ce n'est pas nécessairement le cas. Tant que votre enregistreur statique expose une méthode pour:

  • Injection des classes que vous VOULEZ injecter, ou
  • L'injection du conteneur DI dans un appel de méthode approprié avant de l'exécuter (par exemple dans une méthode similaire à la méthode asp.net global.asax Application_Start), alors tout devrait bien se passer.

Voici un exemple. Prenez le cours suivant pour DI:

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

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

Et voici notre classe statique qui nécessite un enregistreur:

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);
        }


    }

Maintenant, dans un démarrage global de votre application (dans ce cas, dans mon global.asax.cs), vous pouvez instancier votre conteneur DI, puis le transférer à votre classe statique.

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");

        }

Et hop! Vous êtes maintenant opérationnel avec DI dans vos classes statiques.

J'espère que ça aide quelqu'un. Je suis en train de retravailler une application qui utilise BEAUCOUP de classes statiques, et nous l'utilisons avec succès depuis un moment.

23
Chris Smith

C'est un moyen très simple d '"injecter" la fonctionnalité d'un enregistreur statique.

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

Je ne sais pas comment fonctionne Logger, mais vous pouvez généralement utiliser RequestService pour obtenir votre instance. Par exemple en classe abstraite:

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

Il est possible pour le contrôleur, où vous pouvez accéder à HttpContext. 

La deuxième façon est de l’utiliser par exemple dans Startup , où vous pouvez le faire:

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

où serviceCollection est IServiceCollection in dotnet Core.

J'espère que ça a aidé.

0
Petr Tomášek