2010-04-29 17 views
5

Sto costruendo un'applicazione che utilizza AutoFac 2 per DI. Sono stato reading che si dovrebbe evitare di utilizzare un IoCHelper (Localizzatore di servizi) statico.Come evitare Service Locator con AutoFac 2

IoCHelper.cs

public static class IoCHelper 
{ 
    private static AutofacDependencyResolver _resolver; 

    public static void InitializeWith(AutofacDependencyResolver resolver) 
    { 
     _resolver = resolver; 
    } 

    public static T Resolve<T>() 
    { 
     return _resolver.Resolve<T>(); 
    } 
} 

Da risposte a un previous question, ho trovato un modo per contribuire a ridurre la necessità di usare la mia IoCHelper nel mio UnitOfWork attraverso l'utilizzo di Auto-generated Factories. Continuando su questa strada, sono curioso di poter eliminare completamente il mio IoCHelper.

Ecco lo scenario:

ho una classe statica Impostazioni che funge da wrapper mia implementazione di configurazione. Poiché la classe Settings è una dipendenza dalla maggior parte delle altre classi, il wrapper mi impedisce di dover inserire la classe delle impostazioni su tutta la mia applicazione.

Settings.cs

public static class Settings 
{ 
    public static IAppSettings AppSettings 
    { 
     get 
     { 
      return IoCHelper.Resolve<IAppSettings>(); 
     } 
    } 
} 

public interface IAppSettings 
{ 
    string Setting1 { get; } 
    string Setting2 { get; } 
} 

public class AppSettings : IAppSettings 
{ 
    public string Setting1 
    { 
     get 
     { 
      return GetSettings().AppSettings["setting1"]; 
     } 
    } 

    public string Setting2 
    { 
     get 
     { 
      return GetSettings().AppSettings["setting2"]; 
     } 
    } 

    protected static IConfigurationSettings GetSettings() 
    { 
     return IoCHelper.Resolve<IConfigurationSettings>(); 
    } 
} 

C'è un modo per gestire questa situazione senza l'utilizzo di un localizzatore di servizio e senza dover ricorrere ad iniezione AppSettings in ogni classe? Di seguito sono elencati i 3 aree in cui continuano appoggia su ServiceLocator invece di iniezione del costruttore:

  • AppSettings
  • Logging
  • cache

risposta

4

avrei preferito iniettare IAppSettings in ogni classe che ne ha bisogno solo per tenerli puliti dalla dipendenza nascosta su Settings. La domanda è, hai davvero bisogno di cospargere quella dipendenza in ogni classe?

Se si vuole davvero andare con una classe statica Settings, proverei almeno a renderlo test-friendly/simulabile. Considerate questo:

public static class Settings 
{ 
    public static Func<IAppSettings> AppSettings { get; set; } 
} 

E dove si genera il contenitore:

var builder = new ContainerBuilder(); 
... 
var container = builder.Build(); 

Settings.AppSettings =() => container.Resolve<IAppSettings>(); 

Questo permetterebbe di scambiare con falsi durante la prova:

Settings.AppSettings =() => new Mock<IAppSettings>().Object; 

Ora la classe AppSettings (che presumo c'è solo uno di) che potresti fare con un'iniezione regolare del costruttore. Presumo anche che tu voglia veramente fare una risoluzione su ogni chiamata alle proprietà delle impostazioni, iniettando così un delegato di fabbrica che recupera un'istanza quando necessario. Se questo non è necessario, è necessario iniettare direttamente il servizio IConfigurationSettings.

public class AppSettings : IAppSettings 
{ 
    private readonly Func<IConfigurationSettings> _configurationSettings; 

    public AppSettings(Func<IConfigurationSettings> configurationSettings) 
    { 
     _configurationSettings = configurationSettings; 
    } 

    public string Setting1 
    { 
     get 
     { 
      return _configurationSettings().AppSettings["setting1"]; 
     } 
    } 

    public string Setting2 
    { 
     get 
     { 
      return _configurationSettings().AppSettings["setting2"]; 
     } 
    } 
} 
+0

Questo è un buon punto. Sinceramente, probabilmente non ho bisogno di iniettare tali dipendenze in OGNI classe, ma per i casi in cui ho la stessa dipendenza iniettata in un gran numero di classi, ero solo curioso di sapere se esiste qualche buona pratica di DI per questo. –

+1

Vedere la mia risposta aggiornata. A dire il vero, sono stato costretto a farlo in un'occasione: quando non è stato possibile utilizzare l'iniezione del costruttore (il progettista ha richiesto un costruttore senza parametri). –

+0

Soluzione piacevole – Baldy

Problemi correlati