2009-05-15 11 views
6

Używam ogólnego wzorca repozytorium do utrwalania moich danych. Na PageLoad tworzę nowy repozytorium (z IRepository), a na PageUnload, pozbywam się go.Wzór MVP przy użyciu formularzy internetowych i instancji obiektów DI

Czy strona wzorcowa/strona powinna być odpowiedzialna za tworzenie obiektów, które mają zostać przekazane prezenterowi, czy też prezenter powinien się tym zajmować? Bardziej zależy mi na testowaniu prezentera niż na stronie (View), ponieważ łatwiejsze jest kpić z interfejsów przekazywanych do prezentera.

Przykład 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(); 
    } 
} 

Czy są ramy DI takich jak StructureMap lub Ninject pomoc w tej sprawie? Czy byłby odpowiedzialny za usuwanie takich obiektów?

Odpowiedz

6

Ani klasa Page, ani prezenterowie nie powinni zajmować się bezpośrednio zarządzaniem budową lub cyklem życia jakiejkolwiek z jego zależności - to wszystko powinno być obsługiwane przez twój kontener. Ponieważ konstruktor wtrysku nie działa z WebForms, będziesz musiał ujawnić wszelkie potrzebne zależności jako właściwości w klasie. Na przykład, można zmienić klasę:

public partial class _Default : System.Web.UI.Page 
{ 
    protected void Page_Load(object sender, EventArgs e) 
    { 
    } 

    public _DefaultPresenter Presenter { get; set; } 
} 

strona nie powinna potrzebować żadnego odniesienia do repozytorium, jak to będzie wstrzykiwany do prezentera.

Reszta tej odpowiedzi dotyczy StructureMap - szczegóły mogą się różnić w przypadku innych pojemników.

Aby włączyć wstrzyknięcie settera, musisz poinformować StructureMap, które właściwości mają zostać wypełnione. Jednym ze sposobów jest zastosowanie atrybutu [SetterProperty] do samej właściwości. Jednak może to być nieco inwazyjne, aby mieć szczegóły StructureMap w swoich klasach. Innym sposobem jest skonfigurowanie StructureMap, aby wiedziała, które typy właściwości należy wstrzykiwać. Na przykład:

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>()); 
    }); 
} 

Metoda SetAllProperties pozwala poinformować StructureMap, jak rozpoznać właściwości, które ma wypełnić. W tym przypadku mówię StructureMap, aby wstrzyknąć wszystkich prezenterów (zakładając, że wszyscy są w tej samej przestrzeni nazw).

Nadal należy wykonywać zastrzyk ustawiający przy każdym żądaniu.Za pomocą StructureMap używa się metody BuildUp() w celu wstrzyknięcia zależności do istniejącej instancji. Możesz to zrobić w zdarzeniach Init lub Load każdej strony lub klasy bazowej strony, ale znowu jest to inwazyjne. Aby utrzymać pojemnik z waszych klas stronę, można użyć zdarzenia PreRequestHandlerExecute aplikacji (w global.asax lub 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); 
} 

Wreszcie, jeśli chcesz jawnie wyrzucać IRepository, ty mógł poradzić, że w EndRequest imprezy:

protected void Application_EndRequest(object sender, EventArgs e) 
{ 
    var disposable = ObjectFactory.GetInstance<IRepository>() as IDisposable; 
    if (disposable != null) disposable.Dispose(); 
} 

zauważyć, że ta działa poprawnie, ponieważ w inicjalizacji powiedzieliśmy StructureMap do pamięci podręcznej IRepository przez Hybrid, co oznacza „daj mi tę samą instancję dla każdego żądania HTTP (lub wątek, jeśli nie działa w witrynie) ". Po pobraniu elementu IRepository w EndRequest otrzymasz ten sam, który został użyty w żądaniu, i możesz go zutylizować.

2

Tak, warto byłoby zbadać one of the walkthroughs out there of using DI with ASP.NET.

Tak, usuwanie obiektów na żądanie w odpowiednim miejscu jest zwykle zarządzane przez integrację kontenera z ASP.NET.

Typowa konfiguracja polega na tym, że tworzenie obiektów wpływa z wnętrza strony. Zazwyczaj zaznaczasz właściwości [Inject] na swojej klasie Page, ale to zależy od tego, w jaki sposób ułożyłeś swoją triadę. Generalnie prezenter może użyć Constructo Injection, aby zadeklarować, czego potrzebuje, niezależnie od tego, czy jest to test, czy też cotext ASP.NET. Następnie w czasie wykonywania zależności będą spełnione przez DI. W czasie testu możesz nadal korzystać z DI, ale w innych przypadkach może to być bardziej naturalne, po prostu utworzyć kilka podróbek razem z SUT i przekazać je prezenterowi.

Jeśli chodzi o testowanie w trybie TRIEAD, to bardzo przydatne okazało się this MSDN Mag article on using Ninject with xUnit.net by Justin Etheredge, mimo że jest ono skierowane na ASP.NET MVC.

+0

Przepraszamy za niedotrzymanie kodu lub tagów w pytaniu! Przerobiłem to teraz - mam nadzieję, że poprawi się sytuacja! Usunie to, jeśli usuniesz swoje ... –

Powiązane problemy