7

Sto utilizzando il contenitore IoC di Autofac con l'add-on MVC4 che fornisce l'ambito di validità di InstancePerHttpRequest. Tuttavia all'interno del mio progetto ho i thread web, web-api e background worker. Nell'esempio seguente presumo che l'ambito InstancePerHttpRequest non significhi molto quando non proviene da una richiesta web.È possibile specificare più ambiti di durata Autofac in una registrazione?

builder.RegisterType<DatabaseFactory>().As<IDatabaseFactory>() 
    .InstancePerHttpRequest() 

Mi chiedo se è possibile fare qualcosa di simile al seguente esempio e avere il contenitore scegliere l'ambito di vita più appropriato?

builder.RegisterType<DatabaseFactory>().As<IDatabaseFactory>() 
    .InstancePerHttpRequest() 
    .InstancePerApiRequest() 
    .InstancePerDependency(); 

In questo caso ciò che ho intenzione di accadere è se la richiesta proviene da una richiesta web allora sceglierà la portata InstancePerHttpRequest, se si proviene da una richiesta WebAPI sceglierà la portata InstancePerApiRequest e se è usato dai thread worker dell'applicazione utilizzerà l'ambito InstancePerDependency?

Qualche idea se questo o qualcosa di simile è possibile?
Grazie

risposta

10

Questa domanda ha una certa sovrapposizione abbastanza pesante con questi:

Ti consigliamo di controllare quelli fuoriper alcune idee

La risposta breve è: questo genere di cose non è supportato immediatamente. Avrai bisogno di fare un paio di cose.

Opzione: è possibile avere un contenitore diverso per i thread in background. Ciò non consentirebbe di condividere i singleton a livello di applicazione, ma potrebbe essere corretto per l'applicazione.

Opzione: è possibile creare due ambiti di durata del contenitore e fare le diverse registrazioni come parte della chiamata a BeginLifetimeScope. Ciò consentirebbe di condividere i singleton a livello di applicazione e avere ambiti di vita diversi per gli stessi componenti in diversi contesti. Tuttavia, è un po 'più difficile gestire le registrazioni, e avrete bisogno di due diversi localizzatori di servizio (ad es., DependencyResolver) perché ogni contesto logico dovrebbe risolversi dal proprio ambito.

var builder = new ContainerBuilder(); 
builder.RegisterType<AppLevelSingleton>().SingleInstance(); 
var container = builder.Build(); 

// Create a nested lifetime scope for your background threads 
// that registers things as InstancePerDependency, etc. Pass 
// that scope to whatever handles dependency resolution on the thread. 
var backgroundScope = container.BeginLifetimeScope(
    b => b.RegisterType<DatabaseFactory>() 
     .As<IDatabaseFactory>() 
     .InstancePerDependency()); 

// Create a nested lifetime scope for the web app that registers 
// things as InstancePerHttpRequest, etc. Pass that scope 
// as the basis for the MVC dependency resolver. 
var webScope = container.BeginLifetimeScope(
    b => b.RegisterType<DatabaseFactory>() 
     .As<IDatabaseFactory>() 
     .InstancePerHttpRequest()); 
var resolver = new AutofacDependencyResolver(webScope); 
DependencyResolver.SetResolver(resolver); 

Se davvero si voleva ottenere l'immaginazione con questa opzione, è possibile implementare una consuetudine IContainer in grado di rilevare quale contesto è dentro e risolve le cose dal campo di applicazione nidificato appropriata. Questo è il modo in cui il supporto di Autofac multi-tenant funziona. Tuttavia, questa è una soluzione molto più coinvolgente, quindi non scriverò tutto qui. Controllare la sorgente di Autofac per il supporto del multitenant per gli esempi.

Opzione: Si potrebbe utilizzare una sorta "comune minimo denominatore" di registrazione come InstancePerDependency o InstancePerLifetimeScope e saltare l'idea di avere una vita diversa per le diverse parti dell'applicazione.

Si noti che, in questo momento, tecnicamente, internamente, non v'è alcuna differenza tra ciò che InstancePerHttpRequest e InstancePerWebApiRequest fare. Entrambi si riducono esattamente alla stessa cosa e sono effettivamente intercambiabili. (Non posso promettere che sarà sempre così per sempre, ma non so perché dovrebbe cambiare.)

+0

Fantastico! Grazie per la risposta approfondita, questo aiuta molto. – chriskopec

+0

pensa che sarebbe utile. un esempio utilizza l'infrastruttura EF dall'azione dbcontext web api, se chiama la classe che ha bisogno di accedere al database con un nuovo thread, è probabile che sia solo instanceperhttprequest, genererà un'eccezione, quindi è necessario avere la flessibilità per avere InstancePerLifetimeScope. è quasi meglio avere solo InstancePerLifetimeScope. – koo9

Problemi correlati