2016-04-14 14 views
8

Attualmente sto utilizzando Simple Injector per risolvere le dipendenze nei miei progetti Asp.Net Web Api.Risolvi le dipendenze nell'API Web ASP.NET con Simple Injector e IHttpControllerActivator

Dalla documentazione si può configurare in quel modo:

protected void Application_Start() { 
    // Create the container as usual. 
    var container = new Container(); 
    container.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle(); 

    // Register your types, for instance using the scoped lifestyle: 
    container.Register<IUserRepository, SqlUserRepository>(Lifestyle.Scoped); 

    // This is an extension method from the integration package. 
    container.RegisterWebApiControllers(GlobalConfiguration.Configuration); 

    container.Verify(); 

    GlobalConfiguration.Configuration.DependencyResolver = 
     new SimpleInjectorWebApiDependencyResolver(container); 

    // Here your usual Web API configuration stuff. 
} 

I punti principali qui sono per registrare i controllori Web API e impostare un sistema di risoluzione delle dipendenze personalizzato.

Tuttavia Ho appena letto questi articolo di Mark Seemann su come configurare l'iniezione di dipendenza in Asp.Net Web Api:

Da questi articoli, ho Ho appreso che esiste un'opzione migliore rispetto all'implementazione di IDependencyResolver per risolvere le dipendenze API Web. Questa altra opzione è creare un'implementazione di IHttpControllerActivator che funge da adattatore sul contenitore IoC.

Qui è l'implementazione che ho codificato utilizzando SimpleInjector:

public class SimpleInjectorControllerActivator : IHttpControllerActivator 
{ 
    private readonly Container _container; 

    public SimpleInjectorControllerActivator(Container container) 
    { 
     _container = container; 
    } 

    public IHttpController Create(HttpRequestMessage request, 
     HttpControllerDescriptor controllerDescriptor, Type controllerType) 
    { 
     request.RegisterForDispose(_container.BeginExecutionContextScope()); 

     return (IHttpController)_container.GetInstance(controllerType); 
    } 
} 

e nel metodo Application_Start, ho sostituito questa linea:

GlobalConfiguration.Configuration.DependencyResolver = 
    new SimpleInjectorWebApiDependencyResolver(container); 

da questa linea:

GlobalConfiguration.Configuration.Services.Replace(
    typeof(IHttpControllerActivator), 
    new SimpleInjectorControllerActivator(container)); 

Mi piacerebbe sapere se l'implementazione del IHttpControllerActivator i è valido e anche se questo approccio è valido e funzionerà buono come quello normale?

+1

Invece di pubblicare una versione aggiornata, ho aggiornato la domanda con una versione semplificata di SimpleInjectorControllerActivator. – Steven

risposta

3

Sì, l'implementazione è valida.

Fare attenzione a non utilizzare entrambi SimpleInjectorWebApiDependencyResolver e SimpleInjectorControllerActivator nella stessa applicazione. Entrambi iniziano con uno ExecutionContextScope che potrebbe portare ad avere due ambiti all'interno della stessa richiesta web, quindi si escludono a vicenda.

Un vantaggio generale dell'utilizzo di un attivatore di controller sul risolutore di dipendenze è che il contratto del resolver di dipendenze obbliga l'adattatore a restituire null quando non è possibile creare un servizio. Questo è un problema molto comune in cui gli sviluppatori si imbattono, e spesso causa l'eccezione confusione controller does not have a default constructor. Questo problema non esiste quando si utilizza uno IHttpControllerActivator, poiché il contratto obbliga a restituire un valore o a generare un'eccezione.

Il semplice progetto di integrazione API iniettore Web tuttavia, impedisce questo problema con la dipendenza resolver, per non tornare mai null (ma un'eccezione invece) nel caso in cui il servizio richiesto è un controller API (e quindi implicitamente la rottura del contratto s il IDependencyResolver').

Un vantaggio dell'utilizzo di SimpleInjectorDependencyResolver è che diventa più semplice creare gestori di messaggi che operano nell'ambito del contesto di esecuzione, poiché è possibile attivare la creazione di questo ambito chiamando il metodo request.GetDependencyScope().Con l'implementazione corrente, l'ambito viene appena avviato nel momento in cui viene creato il controller, ovvero dopo aver eseguito i gestori. Cambiare questo non è difficile, ma implica cambiare l'attivatore del controller e avere un gestore esterno che avvia l'ambito del contesto di esecuzione (o di nuovo ricade su un resolver di dipendenze che gestisce l'ambito del contesto di esecuzione).

Uno degli argomenti di Mark Seemann è che diventa difficile passare il contesto, che è un punto molto valido, purché il tuo components don't require this context during construction. Ma questo non è un problema che si verifica quando si usa Simple Injector, perché c'è un extension method che ti aiuta ad accedere allo HttpRequestMessage. Pertanto, sebbene l'astrazione IDependencyResolver non sia progettata per ottenere le informazioni contestuali, ci sono modi per ottenere queste informazioni contestuali.

In passato abbiamo deciso di utilizzare un adattatore per lo IDependencyResolver, principalmente perché questa era la pratica comune con tutti i contenitori DI. In parte mi rammarico di questa decisione, ma l'utilizzo di SimpleInjectorDependencyResolver ora è in genere il modo più semplice per collegare Simple Injector all'API Web. Abbiamo preso in considerazione l'aggiunta di uno SimpleInjectorControllerActivator, ma questo non ha avuto alcun vantaggio pratico per la maggior parte degli utenti, mentre dovevamo ancora documentare quando utilizzare cosa. Così abbiamo deciso di restare con l'adattatore del resolver delle dipendenze; un adattatore per l'attivatore è facilmente creato per chiunque ne abbia bisogno, come puoi vedere.

Per ASP.NET Core tuttavia, siamo andati in una direzione diversa, e come potete vedere in the documentation, il pacchetto di integrazione contiene effettivamente un SimpleInjectorControllerActivator fuori dalla scatola. In ASP.NET Core, l'attivatore del controller è il punto di intercettazione perfetto e, grazie alla pipeline di tipo OWIN, un ambito può essere facilmente racchiuso in una richiesta. Quindi, con ASP.NET Core, la pratica consigliata consiste nell'utilizzare l'attivatore del controller come punto di intercettazione.

+0

Grazie Steven! Devo dare un'occhiata al framework principale di asp.net perché mi chiedo se questo approccio sia ancora valido nel contesto principale di asp.net? – Thomas

+0

C'è qualche possibilità di avere questo approccio come l'integrazione web api predefinita usando un semplice iniettore? – Thomas

+0

In questo caso specifico, quali sono i vantaggi dell'utilizzo di 'SimpleInjectorControllerActivator' su' SimpleInjectorWebApiDependencyResolver' se entrambi iniziano un 'ExecutionContext'? Quale tipo di informazione * di contesto * è ottenibile usando il 'ControllerActivator' che non puoi usare' DependencyResolver'? –