Ho usato Ninject in modo specifico in un'applicazione MVC. Il modo in cui lo realizzi con Ninject è nella configurazione o nell'associazione delle tue dipendenze. Quando lo fai, specifichi come vuoi che la vita dell'oggetto sia gestita. Nella maggior parte dei casi di un'app Web, gli oggetti saranno per richiesta come hai indicato nella tua domanda.
Una cosa che ho notato nella tua domanda è che il vostro DomainContext è stato creato da un IDomainService oggetto ed è utilizzato da altri oggetti. Se l'oggetto di servizio di dominio è una sorta di factory per un dominio ,, non si ha un grosso problema - questo diventa un esercizio di come configurare Ninject per fornire oggetti concreti e iniettare dipendenze.
Ecco una guida generale su come si dovrebbe strutturare la vostra applicazione - tenere a mente che non ho piena comprensione delle interfacce e classi:
public class GlobalApplication : NinjectHttpApplication {
protected override void RegisterRoutes(RouteCollection routes) {
// Your normal route registration goes here ...
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = "" }
);
}
// This function is resposible for creating a Ninject kernel. This is where
// the magic starts to happen.
protected override IKernel CreateKernel() {
var modules = new IModule[] {
new AutoWiringModule(),
new AutoControllerModule(
Assembly.GetExecutingAssembly()),
new ServiceModule()
};
return new StandardKernel(modules);
}
}
nota di cui sopra che il modo più semplice per arrivare al lavoro Ninject è derivare la classe dell'applicazione dalla classe NinjectHttpApplication. Sarà necessario modificare il Registro in un metodo di sostituzione e sarà necessario implementare un metodo chiamato CreateKernel. Il metodo CreateKernel è responsabile della restituzione del kernel Ninject che è esso stesso il contenitore IoC.
Nel metodo CreateKernel, i Ninject-forniti AutoControllerModule scansioni assiemi per classi controller MVC e li registra con il contenitore. Ciò significa che le dipendenze su questi controller possono ora essere iniettate da Ninject come è diventato il controller provider per l'applicazione. La classe ServiceModule è una che è necessario creare per registrare tutti i servizi con Ninject. Sto indovinando che sarebbe simile a questa:
internal class ServiceModule : StandardModule {
public override void Load() {
Bind<IDomainService>()
.To<MyDomainService>()
.Using<OnePerRequestBehavior>();
Bind<DomainContext>()
.ToMethod(ctx => ctx.Kernel.Get<IDomainService>().CurrentDomainContext)
.Using<OnePerRequestBehavior>();
Bind<IService>()
.To<MyServiceType>()
.Using<OnePerRequestBehavior>();
}
}
Ninject ha un interfaccia fluida abbastanza espressiva per la configurazione. Si noti sopra che ogni affermazione fondamentalmente associa una classe concreta con un'interfaccia che implementa. La frase "Using" nell'istruzione indica al kernel di Ninject che l'oggetto vivrà solo per la durata della richiesta. Quindi, ad esempio, questo significa che ogni volta che un oggetto IDIDomainService viene richiesto dal kernel di Ninject durante la stessa richiesta, verrà restituito lo stesso oggetto.
Per quanto riguarda gli oggetti di contesto, mi sto rendendo conto che il tuo servizio di dominio crea questi contesti e agisce come una sorta di fabbrica. A tale proposito, ho associato le istanze DomainContext alle classi sopra riportate per ottenere il valore di una proprietà denominata CurrentDomainContext dal IDomainService. Questo è ciò che la lambda sopra compie. Il bello del binding "ToMethod" in Ninject è che si ha accesso ad un oggetto di contesto di attivazione di Ninject che consente di risolvere gli oggetti usando il kernel. Questo è esattamente ciò che facciamo per ottenere il contesto attuale del dominio.
I passaggi successivi sono per garantire che gli oggetti accettino correttamente le dipendenze. Ad esempio, tu dici che ITrainingService viene utilizzato solo nella classe TrainingController. Quindi, in tal caso, mi assicuro che lo TrainingController disponga di un costruttore che accetta un parametro ITrainingService. In tale costruttore, è possibile salvare il riferimento a ITrainingService in una variabile membro. Come in:
public class TrainingController : Controller {
private readonly ITrainingService trainingService;
public TrainingController(ITrainingService trainingService) {
this.trainingService = trainingService;
}
// ... rest of controller implementation ...
}
Ricordate che Ninject ha già registrato tutti i controller con il kernel Ninject, in modo che quando si crea questo controller ed è vengono richiamate le azioni, avrete un riferimento al ITrainingService in via della variabile membro trainingService.
Spero che questo ti aiuti. L'utilizzo di contenitori IoC può a volte diventare piuttosto confuso. Nota, consiglio vivamente di dare un'occhiata allo Ninject documentation - è un'introduzione molto ben scritta su Ninject e sui concetti DI/IoC. Ho anche omesso di discutere su AutoWiringModule mostrato sopra; tuttavia, Nate Kohari (creatore di Ninject) ha a good write-up sul suo blog su questa funzione.
Buona fortuna!
Collegamento interrotto, consiglio ben superato dalla risposta completa di Peter. (Un errore specifico consiste nel suggerire comportamenti di attivazione (l'InRequestScope nella risposta di Peter è l'approccio corretto)). Suggerisci di eliminare questa risposta. (Non erroneamente in modo errato, quindi non farlo, ma non lontano da esso) –