Né la classe Page né i relatori dovrebbero occuparsi direttamente della gestione della costruzione o del ciclo di vita di una delle sue dipendenze, che dovrebbero essere gestite dal contenitore. Poiché l'iniezione del costruttore non funziona con WebForms, è necessario esporre tutte le dipendenze necessarie come proprietà sulla classe. Ad esempio, è possibile modificare la classe per:
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
public _DefaultPresenter Presenter { get; set; }
}
La pagina non dovrebbe aver bisogno di alcun riferimento al repository, in quanto sarà iniettato il presentatore.
Il resto di questa risposta è specifico di StructureMap: i dettagli possono differire per altri contenitori.
Per abilitare l'iniezione setter, è necessario specificare a StructureMap quali proprietà devono essere compilate. Un modo è quello di applicare l'attributo [SetterProperty] alla proprietà stessa. Tuttavia, questo può sembrare un po 'invasivo avere dettagli di StructureMap all'interno delle classi. Un altro modo è configurare StructureMap in modo che sappia quali tipi di proprietà iniettare. Per esempio:
protected void Application_Start(object sender, EventArgs e)
{
ObjectFactory.Initialize(x =>
{
x.Scan(scan =>
{
scan.TheCallingAssembly();
scan.WithDefaultConventions();
});
x.ForRequestedType<IRepository>().TheDefaultIsConcreteType<Repository>().CacheBy(InstanceScope.Hybrid);
x.SetAllProperties(set => set.WithAnyTypeFromNamespaceContainingType<IRepository>());
});
}
Il metodo SetAllProperties consente di indicare StructureMap come riconoscere le proprietà che dovrebbe popolano. In questo caso, sto dicendo a StructureMap di iniettare tutti i relatori (supponendo che siano tutti nello stesso spazio dei nomi).
È ancora necessario eseguire l'iniezione setter su ogni richiesta.Con StructureMap, si utilizza il metodo BuildUp() per iniettare dipendenze in un'istanza esistente. Potresti farlo negli eventi Init o Load di ogni pagina o classe di base della pagina, ma di nuovo, ciò sembra invasivo. Per mantenere completamente il contenitore fuori delle classi di pagina, è possibile utilizzare l'evento PreRequestHandlerExecute dell'applicazione (in Global.asax o un IHttpModule):
protected void Application_PreRequestHandlerExecute(object sender, EventArgs e)
{
var application = (HttpApplication)sender;
var page = application.Context.CurrentHandler as Page;
if (page == null) return;
ObjectFactory.BuildUp(page);
}
Infine, se si vuole esplicitamente Smaltire vostra IRepository, è poteva gestire che in caso EndRequest:
protected void Application_EndRequest(object sender, EventArgs e)
{
var disposable = ObjectFactory.GetInstance<IRepository>() as IDisposable;
if (disposable != null) disposable.Dispose();
}
Nota che questo funziona correttamente perché nella inizializzazione abbiamo detto StructureMap di memorizzare nella cache IRepository da Hybrid, che significa "mi danno la stessa istanza per ogni richiesta HTTP (o filo, se non in esecuzione all'interno di un sito Web) ". Quando recuperi l'IRepository in EndRequest, riceverai lo stesso usato in tutta la richiesta e potrai disporlo.
Ci scusiamo per non aver visto il codice o i tag nella tua domanda! L'ho rielaborato ora - spero che migliori le cose! Cancellerà questo se elimini il tuo ... –