2009-05-15 6 views
6

Ich verwende das generische Repository-Muster, um meine Daten zu persistieren. Auf dem PageLoad erstelle ich ein neues Repository (aus IRepository) -Objekt, und auf PageUnload, entsorge ich es.MVP-Muster mit Webforms und DI-Objekt Instanziierung

Sollte die MasterPage/Seite für die Instanziierung der Objekte zuständig sein, die an den Moderator übergeben werden sollen, oder sollte der Moderator dafür verantwortlich sein? Mir geht es eher darum, den Moderator zu testen als die Seite (Ansicht), da es einfacher ist, die an den Moderator übergebenen Schnittstellen zu überspielen.

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

Würde ein DI-Framework wie StructureMap oder Ninject Hilfe in diesem Fall? Wäre es für die Entsorgung solcher Objekte zuständig?

Antwort

6

Weder die Page-Klasse noch die Präsentatoren sollten direkt mit der Verwaltung der Konstruktion oder des Lebenszyklus von Abhängigkeiten zu tun haben - dies sollte alles von Ihrem Container gehandhabt werden. Da die Konstruktorinjektion nicht mit WebForms funktioniert, müssen Sie alle erforderlichen Abhängigkeiten als Eigenschaften für die Klasse verfügbar machen. Zum Beispiel könnten Sie Ihre Klasse ändern:

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

    public _DefaultPresenter Presenter { get; set; } 
} 

Die Seite sollte jede Bezugnahme auf das Repository nicht benötigen, wie es in den Präsentator injiziert wird.

Der Rest dieser Antwort ist spezifisch für StructureMap - Details können für andere Container abweichen.

Um die Setter-Injektion zu aktivieren, müssen Sie StructureMap mitteilen, welche Eigenschaften aufgefüllt werden sollen. Eine Möglichkeit besteht darin, das Attribut [SetterProperty] auf die Eigenschaft selbst anzuwenden. Dies kann jedoch ein wenig aufdringlich wirken, wenn Sie StructureMap-Details in Ihren Klassen verwenden möchten. Eine andere Möglichkeit besteht darin, StructureMap so zu konfigurieren, dass es weiß, welche Eigenschaftentypen injiziert werden sollen. Zum Beispiel:

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

Die SetAllProperties Methode ermöglicht es Ihnen StructureMap zu sagen, wie die Eigenschaften zu erkennen, sollte es füllen. In diesem Fall rate ich StructureMap, alle Präsentatoren zu injizieren (vorausgesetzt, sie befinden sich alle im selben Namensraum).

Sie müssen die Setter-Injektion bei jeder Anforderung noch durchführen.Mit StructureMap verwenden Sie die BuildUp() -Methode, um Abhängigkeiten in eine vorhandene Instanz einzufügen. Sie könnten dies in den Init- oder Load-Ereignissen jeder Seite oder in einer Seitenbasisklasse tun, aber auch das fühlt sich invasiv an. Um den Behälter zu halten vollständig aus Ihrer Seite Klassen, können Sie die PreRequestHandlerExecute Ereignis der Anwendung (in global.asax oder eine 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); 
} 

Schließlich, wenn Sie möchten ausdrücklich Entsorgen Sie Ihre IRepository, Sie dass in der Endrequest-Ereignis behandeln könnte:

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

Beachten Sie, dass dies funktioniert, weil in der Initialisierung wir StructureMap sagte IRepository von Hybrid zwischenzuspeichern, die für jede HTTP-Request (oder Thread „Gib mir die gleiche Instanz bedeutet, wenn nicht innerhalb einer Website läuft) ". Wenn Sie das IRepository in EndRequest abrufen, erhalten Sie dasselbe, das während der gesamten Anfrage verwendet wurde, und Sie können es entsorgen.

2

Ja, es würde sich sehr lohnen, nach one of the walkthroughs out there of using DI with ASP.NET zu suchen.

Ja, die Bereitstellung von per-Request-Verhalten-Objekten an der entsprechenden Stelle wird in der Regel durch die Integration des Containers mit ASP.NET verwaltet.

Die typische Anordnung besteht darin, dass die Objekterzeugung von der Seite und /Module s nach innen fließt. Im Allgemeinen markieren Sie Eigenschaften [Inject] auf Ihrer Page Klasse, aber es hängt davon ab, wie Sie Ihre Triade angeordnet haben. Der Presenter kann Constructo Injection im Allgemeinen verwenden, um zu deklarieren, was er benötigt, unabhängig davon, ob es sich um den Test oder den ASP.NET-Cotext handelt. Zur Laufzeit werden dann die Abhängigkeiten von der DI erfüllt. Zur Testzeit können Sie immer noch DI verwenden, aber in anderen Fällen ist es vielleicht natürlicher, nur ein paar Fakes zusammen mit dem SUT zu erstellen und diese an den Presenter zu übergeben.

In Bezug auf Triead-Anordnungen wr Test, fand ich this MSDN Mag article on using Ninject with xUnit.net by Justin Etheredge sehr nützlich, obwohl es auf ASP.NET MVC ausgerichtet ist.

+0

Entschuldigung, dass Sie den Code oder die Tags in Ihrer Frage nicht angesehen haben! Habe es jetzt überarbeitet - hoffe das verbessert die Sache! Wird dies löschen, wenn Sie Ihre löschen ... –