Enter presenter in Model-View-Presenter with StructureMap

I have implemented my own copy of the model view presentation template (in the form of factory web client software), so I can use my own DI infrastructure instead of binding to the WCBF ObjectBuilder, which I had a lot of problems with. I came up with several ways to do this, but none of them are particularly pleasing to me. I wanted to know if anyone has any other ideas.

Solution # 1a

Uses an HttpModule to intercept context.PreRequestHandlerExecute to call ObjectFactory.BuildUp (HttpContext.Current.Handler)

public partial class _Default : Page, IEmployeeView { private EmployeePresenter _presenter; private EmployeePresenter Presenter { set { _presenter = value; _presenter.View = this; } } } 

Decision No. 1b

Call extension on page load instead of using HttpModule

 public partial class _Default : Page, IEmployeeView { private EmployeePresenter _presenter; private EmployeePresenter Presenter { set { _presenter = value; _presenter.View = this; } } protected void Page_Load(object sender, EventArgs e) { ObjectFactory.BuildUp(this); } } 

Solution # 1c

Access to the presenter via the property allows Getter to create a BuildUp, if necessary.

 public partial class _Default : Page, IEmployeeView { private EmployeePresenter _presenter; public EmployeePresenter Presenter { get { if (_presenter == null) { ObjectFactory.BuildUp(this); } return _presenter; } set { _presenter = value; _presenter.View = this; } } } 

Decision number 2

 public partial class _Default : Page, IEmployeeView { private EmployeePresenter _presenter; private EmployeePresenter Presenter { get { if (_presenter == null) { _presenter = ObjectFactory.GetInstance<EmployeePresenter>(); _presenter.View = this; } return _presenter; } } } 

Solution No. 2b

 public partial class _Default : Page, IEmployeeView { private EmployeePresenter _presenter; private EmployeePresenter Presenter { get { if (_presenter == null) { Presenter = ObjectFactory.GetInstance<EmployeePresenter>(); } return _presenter; } set { _presenter = value; _presenter.View = this; } } } 

Edit : added solution 1c, 2b

+6
c # dependency-injection mvp structuremap
source share
4 answers

I would use solution # 1b and create a superscript for all pages so that DRY initializes the presentation a bit more, for example:

Page Code:

 public partial class _Default : AbstractPage, IEmployeeView { private EmployeePresenter presenter; private EmployeePresenter Presenter { set { presenter = value; presenter.View = this; } } protected override void Do_Load(object sender, EventArgs args) { //do "on load" stuff } } 

Abstract Page Code:

 public abstract class AbstractPage : Page { protected void Page_Load(object sender, EventArgs e) { ObjectFactory.BuildUp(this); this.Do_Load(sender,e); //template method, to enable subclasses to mimic "Page_load" event } //Default Implementation (do nothing) protected virtual void Do_Load(object sender, EventArgs e){} } 

With this solution, you only have a presenter initialization (created by ObjectFactory) in one class, if you need to change it later, you can do it easily.

Edit:

Should Do_Load be abstract or virtual?

The template method initially claims that the method must be abstract in order to force subclasses to implement it, adhering to the superclass agreement. (see Wikipedia example โ€œMonopolyโ€ and โ€œGameโ€).

On the other hand, in this particular case, we do not want to force the user class to override our method, but give it a chance to do this. If you declare it abstract, many classes will be required to override the method to leave it empty (this is clearly the smell of code). Thus, we provide a reasonable default value (do nothing) and make the method virtual.

+7
source share

I used the base class of the page:

 protected override void OnInit(EventArgs e) { StructureMap.ObjectFactory.BuildUp(this); base.OnInit(e); } 

The base class approach also works with user controls, which in itself kept me from the module (I did not want to have two ways to configure it). For the page, this

 public partial class Employee : View, IEmployeeView { public ViewPresenter Presenter { get; set; } private void Page_Load(object sender, EventArgs e){} } 

I am inserting a view through the constructor. To avoid the circular link problem in the config structure, just use this helper method:

 static T GetView<T>() { return (T) HttpContext.Current.Handler; } 

In the mapmap configuration, use the convention for both the presenter and the view injection.

+1
source share

I also created my own MVP infrastructure. I found for me the best way to use generics with a base class. By specifying the type of Presenter in the definition of a generic class, I can skip most of the code that your every sentence requires.

However, I do not like some things. The definition of a class can be quite complicated and difficult to read for beginners. I have also not fully developed a good way to use the event model on the base page.

Sorry, I do not have the code for you here, but I can publish it for you if you want. I also have an old version of code hosted at www.codeplex.com/aspnetmvp if you want to see how it works.

+1
source share

Thank you all for your valuable contribution. Your answers gave me valuable ideas to come together in my final decision, and here is what I came up with:

 public abstract class ViewBasePage<TPresenter, TView> : Page where TPresenter : Presenter<TView> { protected TPresenter _presenter; public TPresenter Presenter { set { _presenter = value; _presenter.View = GetView(); } } /// <summary> /// Gets the view. This will get the page during the ASP.NET /// life cycle where the physical page inherits the view /// </summary> /// <returns></returns> private static TView GetView() { return (TView) HttpContext.Current.Handler; } protected override void OnPreInit(EventArgs e) { ObjectFactory.BuildUp(this); base.OnPreInit(e); } } 

And inherited from my original page:

 public partial class _Default : ViewBasePage<EmployeePresenter, IEmployeeView>, IEmployeeView { protected void Page_Load(object sender, EventArgs e) { if (!Page.IsPostBack) { _presenter.OnViewInitialized(); } _presenter.OnViewLoaded(); Page.DataBind(); } #region Implementation of IEmployeeView ... #endregion } 
0
source share

All Articles