Passaggio dei servizi utilizzando Iniezione delle dipendenze e Pattern di fabbrica in ASP.NET

Sto usando ASP.NET Core, so che tale meccanismo di Logging è già fornito dal framework, ma usando questo per illustrare il mio problema.

Sto usando il tipo di modello Factory per creare la class Logger, dal momento che non conosco il tipo di registrazione (perché è memorizzata nel DB).

Il contratto di ILogger

Log(string msg) 

Quindi LoggerFactory restituirà un ILogger dopo aver creato un Logger basato sul parametro passato dal DB:

 public class LoggerFactory { public static Contracts.ILogger BuildLogger(LogType type) { return GetLogger(type); } //other code is omitted, GetLogger will return an implementation of the related logger 

Ora, quando ho bisogno di usare il Logger, devo farlo in questo modo:

  public class MyService { private ILogger _logger public MyService() { _logger = LoggerFactory.BuildLogger("myType"); } 

Ma, ho intenzione di mantenere le mie lezioni senza alcuna istanziazione, ho bisogno di usare COS di costruzione in MyService e ho bisogno di iniettare tutte le dipendenze all’avvio:

  services.AddTransient (); 

Ma questo non funzionerà, dobbiamo passare una concreta implementazione. Come fare quel lavoro usando DI, esiste un approccio migliore per implementarlo?

    Ci sono un paio di errori nel tuo approccio:

    • I tuoi servizi dipendono dal tipo di LoggerFactory concreto che è una violazione del Principio LoggerFactory dipendenza .
    • L’esecuzione di questa inizializzazione aggiuntiva può rendere inaffidabile la creazione del grafo degli oggetti, mentre i costruttori dell’iniezione dovrebbero essere semplici .
    • Nasconde il fatto che ILogger è il vero servizio da cui dipende il tuo consumatore. Ciò rende il sistema più difficile da testare, difficile da mantenere e complica l’analisi del grafo degli oggetti.
    • L’uso di una fabbrica è un odore, poiché le fabbriche non sono quasi mai la soluzione giusta .

    Invece, il tuo servizio dovrebbe apparire come segue:

     public class MyService { private ILogger _logger; public MyService(ILogger logger) { _logger = logger; } } 

    Questo semplifica notevolmente tutti i consumatori che dipendono da ILogger . Ciò significa anche che ottenere il giusto ILogger per MyService diventa una responsabilità della Composizione Root , che è il posto giusto per avere questa conoscenza.

    Significa tuttavia che potrebbe essere necessario spostarsi dal contenitore DI incorporato di ASP.NET Core a una libreria DI più ricca di funzionalità, poiché il contenitore integrato non è in grado di effettuare una registrazione sensibile al contesto per ILogger pur avendo la libreria collega automaticamente anche altre dipendenze del costruttore.

    Con il contenitore DI di base ASP.NET, è ansible colbind a mano i servizi solo tramite un delegato. Per esempio:

     services.AddTransient(c => new MyService( BuildLogger(typeof(MyService).Name), c.GetRequiredService(), c.GetRequiredService());