11

Ho un modulo HTTP personalizzato. Vorrei iniettare il logger usando il mio framework IoC, così posso registrare gli errori nel modulo. Tuttavia, ovviamente non ho un costruttore, quindi non posso iniettarlo in questo. Qual è il modo migliore per farlo?Iniezione della dipendenza IoC nel modulo HTTP personalizzato - come? (ASP.NET)

Se è necessario il contenitore IoC specifico, attualmente utilizzo Windsor, ma potrebbe passare presto a AutoFac.

Grazie

+0

Si potrebbe utilizzare un localizzatore di servizio, dare un'occhiata a questa domanda: [Differenza tra l'iniezione di dipendenza e di servizio modello locator] (http://stackoverflow.com/questions/1557781/ cosa è-differenza-tra-dipendenza-iniezione-e-servizio-locator-patter) – FinnNk

risposta

2

Si potrebbe passare le dipendenze richieste tramite il contesto HttpApplication passato a voi con il metodo Init ...

public class MyHttpModule : IHttpModule 
{ 
    public void Init(HttpApplication context) 
    { 
     var dependency = (IDependency)context.Context.Items["dependency"]; 
     // consume dependency... 
    } 

    public void Dispose() 
    { 
    } 
} 
+2

-1 perché è molto difficile deridere le dipendenze in questo modo –

+0

@Mauricio Scheffer: Forse, ma poi basta implementare il modulo come Humble Executable. Preferisco quell'approccio all'uso dell'iniezione statica. La gente pensa che aiuti la testabilità, ma fa davvero male. –

+1

Humble Executable funziona sicuramente bene in questo caso, aggiungerei questa informazione alla risposta. Tuttavia, puoi avere la tua torta e mangiarla anche tu, vedi la mia soluzione. –

10

prima volta che ho visto l'iniezione di dipendenza per HttpModules in primavera. NET (non pubblicizzare però questo framework). L'idea è di avere un HttpModule speciale che inietta le dipendenze da altri HttpModule-s a livello di applicazione.

Unfortunatelly versione corrente di Autofac.Integration.Web non supporta questa, ma si può facilmente farlo da soli:

public class MyModule : IHttpModule 
{ 
    public void Dispose() 
    {    
    } 

    public void Init(HttpApplication context) 
    { 
     Assert.IsNotNull(MyService); 
    }   

    public IMyService MyService { get; set; } 
} 

public class HttpModuleInjectionModule : IHttpModule 
{ 
    public void Dispose() 
    {    
    } 

    public void Init(HttpApplication context) 
    { 
     var containerProviderAccessor = context as IContainerProviderAccessor; 

     if(containerProviderAccessor == null) 
      throw new InvalidOperationException("HttpApplication should implement IContainerProviderAccessor"); 

     var rootContainer = containerProviderAccessor.ContainerProvider.ApplicationContainer; 

     foreach (string moduleName in context.Modules.AllKeys) 
      rootContainer.InjectProperties(context.Modules[moduleName]); 
    } 
} 

public class Global : HttpApplication, IContainerProviderAccessor 
{ 
    static IContainerProvider _containerProvider; 

    protected void Application_Start(object sender, EventArgs e) 
    { 
    var builder = new ContainerBuilder(); 
    builder.Register<MyService>().As<IMyService>(); 
    _containerProvider = new ContainerProvider(builder.Build()); 
    } 

    public IContainerProvider ContainerProvider 
    { 
    get { return _containerProvider; } 
    } 
} 

HttpModuleInjectionModule deve essere registrata prima di altri HttpModule-s nel web.config:

<httpModules> 
    <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> 
    <add name="HttpModuleInjection" type="WebTest.HttpModuleInjectionModule, WebTest"/> 
    <add name="ContainerDisposal" type="Autofac.Integration.Web.ContainerDisposalModule, Autofac.Integration.Web"/> 
    <add name="PropertyInjection" type="Autofac.Integration.Web.PropertyInjectionModule, Autofac.Integration.Web"/> 
    <add name="MyModule" type="WebTest.MyModule, WebTest"/> 
    </httpModules> 

Sono sicuro che puoi fare cose simili a Windsor. La differenza sarebbe nel modo in cui accedi al tuo root container da HttpModuleInjectionModule.

+0

questo è abbastanza limitato, non può fare l'iniezione del costruttore. –

1

Sono curioso della risposta di andrey-tsykunov, ma non ho il rappresentante per commentarlo.

Sto provando a familiarizzare con IoC e DI, quindi potrei mancare qualcosa, ma non sarebbe più semplice utilizzare IContainerProviderAccessor da MyModule, piuttosto che creare un altro modulo?

Ad esempio:

public class MyModule : IHttpModule 
{ 
    public void Dispose() 
    {    
    } 

    public void Init(HttpApplication context) 
    { 
     Assert.IsNotNull(MyService); 

     var containerProviderAccessor = context as IContainerProviderAccessor; 

     if (accessor != null) 
     { 
      IContainer container = containerProviderAccessor.ContainerProvider.ApplicationContainer; 
      MyService = container.Resolve<IMyService>(); 
     } 
    } 

    private IMyService MyService { get; set; } 
} 
+4

Non stai facendo l'iniezione della dipendenza qui, stai facendo la posizione del servizio. –

+3

Sembra che tu abbia risolto la cosa del rappresentante: P –