2009-05-15 13 views
6

Sto utilizzando il modello di repository generico per mantenere i miei dati. Nel PageLoad, sto creando un nuovo oggetto Repository (da IRepository), e su PageUnload lo caccio.Pattern MVP utilizzando webform e istanza di oggetti DI

La MasterPage/Page deve essere incaricata di istanziare gli oggetti da passare al presentatore o il responsabile deve essere responsabile di questo? Sono più interessato a testare il presentatore rispetto alla pagina (Vista) poiché è più facile prendere in giro le interfacce passate al presentatore.

Esempio Page

public partial class _Default : System.Web.UI.Page 
{ 
    private IRepository _repo; 
    protected void Page_Load(object sender, EventArgs e) 
    { 
     if (_repo == null) 
      _repo = new Repository(); 
     ConnectPresenter(); 
    } 

    private void ConnectPresenter() 
    { 
     _DefaultPresenter presenter = new _DefaultPresenter(_repo); 
    } 

    private void Page_Unload(object sender, EventArgs e) 
    { 
     if (_repo != null) 
      _repo.Dispose(); 
    } 
} 

Sarebbe un quadro DI come StructureMap o Ninject aiuto in questo caso? Sarebbe incaricato di smaltire oggetti come questo?

risposta

6

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.

2

Sì, varrebbe la pena indagare su one of the walkthroughs out there of using DI with ASP.NET.

Sì, lo smaltimento degli oggetti di comportamento per richiesta al punto appropriato viene generalmente gestito dall'integrazione del contenitore con ASP.NET.

La disposizione tipica è che la creazione di oggetti fluisce dalla pagina e Application/s Module attivo. In genere contrassegni le proprietà [Inject] sulla tua classe Page, ma dipende da come hai organizzato la tua terna. In genere, Presenter può utilizzare Constructo Injection per dichiarare ciò di cui ha bisogno indipendentemente dal test o dal cotext di ASP.NET. Quindi in fase di esecuzione, le dipendenze saranno soddisfatte dal DI. Al momento del test, è ancora possibile utilizzare DI, anche se in altri casi potrebbe essere più naturale creare semplicemente un gruppo di falsi insieme al SUT e passare quelli al presentatore.

Per quanto riguarda gli arrangiamenti di treppiedi durante i test, ho trovato che this MSDN Mag article on using Ninject with xUnit.net by Justin Etheredge è molto utile, anche se è stato assegnato a ASP.NET MVC.

+0

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 ... –

Problemi correlati