Model View Presenter (MVP) – Tips from trenches (TFT) – Base types(Part 1)

 

 

Intro

RAD tooling style Microsoft is supporting last couple of years usually leads to the code where presentation and bossiness logic are mixed and tightly coupled which makes testability, maintainability and sustainability much more harder then they should be. In case you’ve had to work in the past with web pages containing couple of thousands lines in code behind you will know exactly what problems I am referring to here. In case not, please let me know what is the name of the place where you work 🙂

One way to tackle that is using the Model View Presenter UI design pattern which provides clean separation between UI and domain logic and as a result of that come testability of the “UI code”, SRP and SOC principles appliance, clean domain model etc…

In case you never heard about MVP pattern, before continuing reading this blog posts you might want to take some time and look at Model View Presenter (MVP) pattern (L100). In case you heard about it, but you are not familiar very much with what exactly it is, you might want to read about Supervising controller and Passive view. In case you are wondering what is the difference between MVP and “the one everyone talks about MVC”, I tried to explain that here. In case you are looking for advices on building new web site based on MVP pattern, the guys at Microsoft did great job with Web Client Software Factory, so check that out.In case you knew already all this but never had chance to apply MVP in real world and/or you face some problems applying it in real world, you are at the right place 🙂

Purpose of this blog post series is to share with community my experiences on the typical hurdles I was witnessing during the MVP based web site implementation.

Today’s hurdle: MVP wire up code noiseimage

(Source code used in today example can be downloaded from here)

Basically there are couple of ways to wire up  presenter and the view, but after some experiments with constructor based injection and after working for some time with Web Client Software Factory (WCSF) I kind a like setter based dependency injection style.

Let take a look at that code noise through an example of simple web site with just a single Default page which would have a separate class library project containing view interface (which btw I name following the rule IPageNameView ) and presenter (convention I follow here is PageNameViewPresenter)

The view interface could look for this example something like this:

namespace Presenters
{
    public interface IDefaultView
    {
        int SomeValue { get; set; }
    }
}

 

 

Here’s the presenter code example similar to a lot of presenters I’ve seen

namespace Presenters
{
    public class DefaultViewPresenter
    {
        private IDefaultView _view;

        public IDefaultView View
        {
            get { return _view; }
            set { _view = value; }
        }

        public void SomeMethod()
        {
            if (View.SomeValue>0)
            {
                // do something
            }
        }

        public void OnViewInitialized()
        {
            // do something on view init
        }

        public void OnViewLoaded()
        {
            // do something on view load
        }
    }
}

Interesting points of presenter code:

  • Presenter has a View property of IDefaultView type
  • how presenter uses  view inside of SomeMethod()
  • existence of two methods which are supposed to be called upon page load and init

Let’s take a peek now at how the view (default web page) would end wired up with the presenter

using System;
using System.Web.UI;
using Presenters;

namespace WebApplication1
{
    public partial class _Default : Page, IDefaultView
    {
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            Presenter = new DefaultViewPresenter();
        }

        protected void Page_Load(object sender, EventArgs eventArgs)
        {
            if (!Page.IsPostBack)
            {
                Presenter.OnViewInitialized();
            }
            Presenter.OnViewLoaded();
        }

        private DefaultViewPresenter _presenter;

        public DefaultViewPresenter Presenter
        {
            get { return _presenter; }
            set
            {
                _presenter = value;
                _presenter.View = this;
            }
        }

        protected void Something_Clicked(object sender, EventArgs eventArgs)
        {
            Presenter.SomeMethod();
        }

        // Here goes implementation of IDefaultView


    }
}

Key points regarding view code:

  • OnInit method sets the Presenter property value to new DefaultViewPresenter instance
  • Inside of Presenter property setter View property of the presenter gets web page pointer casted to IDefaultView.
    Effectively, presenter gets injected with a view implicitly cast to view interface
  • Inside of page load method, presenter OnViewInitialized method is get called if the page is not postbacking itself
  • Inside of page load method, presenter OnViewLoaded method is get called regardless of postback
  • Last interesting moment here is how Presenter is get called  from a view in Something_Clicked event handler

Hurdle summary

Writing all of this code for every web page and every control (I will speak about this in later posts) is very tedious and repetitive task. Using WCSF helps a bit because code similar to this gets generated but still that’s a lot of lines written just in order to enable us to start to work on a page.

Luckily, there’s a solution 🙂

The solution of today’s hurdle would be encapsulating all of the code noise in set of base classes.

The design goals here are:

  • define generic presenter which would be using generic view interfaces
  • define generic view which would perform automatic wire up to generic presenter

Let’s see one way how this can be done….

(My solution is based on Mario Szklanny’s Web Client Software factory solution, which I adopted for use outside of WCSF)

Generic presenter

The code related to this goal will be stored in a class library which I call Framework.

Purpose of Framework assembly is to contain all the basic functionality required for most of the code regardless of it is web/UI related or not. image

That’s why beside the MVP related code there would be (in my case):

  • ServiceLocator type (with code similar to what was described in  DFT Unity  blog post)
  • BaseClass and BaseCollection (very light, providing only basic functionality I personally use in debugging. Definitely NOT supposed to be  god class
  • More other things I won’t mention here (I would be adding them in the upcoming posts so I don’t want to spoil the surprise :))

(In case you are puzzled with reasons behind having Rhino.Mocks reference in Framework, check this out)

Key concern related to this class: No heavy dependencies and definitely no System.Web related references. This component is supposed to be able to be referenced by any component in application

The IPresenter interface defines very simple generic presenter attributes

namespace Vuscode.Framework.ModelViewPresenter
{
    public interface IPresenter
    {
        object View { get; set; }

        void OnViewInitialized();

        void OnViewLoaded();
    }
}

OnViewInitialized and OnViewLoaded are methods we saw in above code as the ones handling calls from Page_Load method. The reason behind the fact that View  is of object type is that we can box any class to object type so we can store reference to boxed form of any view

Generic Presenter class implementing the IPresenter interface could look like this

namespace Vuscode.Framework.ModelViewPresenter
{
    public abstract class Presenter<TView> : IPresenter
    {
        public TView View { get; set; }

        #region IPresenter Members

        object IPresenter.View
        {
            get { return View; }
            set { View = (TView) value; }
        }

        public virtual void OnViewInitialized()
        {
            /* do nothing*/
        }

        public virtual void OnViewLoaded()
        {
            /* do nothing*/
        }

        #endregion
    }
}

Looking at the code above one could realize next things:

  • Presenter class is abstract generic class accepting  TView generic parameter and implementing IPresenter interface
  • The two methods are implemented as virtual because we don’t want to enforce implementing this methods in each one of presenters inheriting generic presenter because some of them might not need some of those methods
  • The object View property defined by IPresenter interface is implemented explicitly which effectively hides it from the classes inheriting generic presenter
  • The fact that TView View property is public, combined with mentioned explicit implementation of the object View property effectively constrained View to TView

Generic viewimage

One of the main design principles I am trying to stay with is that Presenter assembly is not allowed to be dependable on System.Web directly or indirectly and therefore due to the fact that Presenters will reference the Framework, I can not put there generic view. 

The reason why I can not do that is based upon the fact that each one of the pages would inherit from that base generic view, so generic view needs to inherit from System.Web.UI.Page

All of the “base web UI” functionality I would keep in component called “Web.Base”

From the solution explorer snapshot on the right side, we can see that project consists of 3 base views: page, control and master page. (Yes, I am applying MVP pattern even on the master page)

using System;
using Vuscode.Framework.ModelViewPresenter;

namespace Vuscode.Web.Base
{
    public abstract class ViewBasePage<TPresenter> : LegacyBasePage
						where TPresenter : IPresenter, new()
    {
        private TPresenter _presenter;

        protected ViewBasePage()
        {
            Presenter = new TPresenter();
        }

        public TPresenter Presenter
        {
            get { return _presenter; }
            set
            {
                _presenter = value;
                _presenter.View = this;
            }
        }

        protected virtual void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                Presenter.OnViewInitialized();
            }
            Presenter.OnViewLoaded();
        }

    }
}

Interesting moments here are:image

  • ViewBasePage is  abstract generic page where the generic parameter is constrained to type implementing IPresenter interface
  • ViewBasePage inherits from LegacyBasePage
    Most of us have some base page already in our web sites. This illustrates that the ViewBasePage should inherit from that page and then all of the MVP pages would therefore get access to that legacy base page and inherit all of the MVP related code
  • Rest of the code is the same code we had on default page just pulled out to base page level

Code for generic view of control and master page is exactly the same as the page one with only difference from which base type they would inherit (UserControl or MasterPage)

Solution in action

Having Framework and Web.Base component built, would enable us to make changes in presenter and view which would cause them to look like this at the end

View (Default web page)

using System;
using System.Web.UI;
using Presenters;
using Vuscode.Web.Base;

namespace WebApplication1
{
    public partial class _Default : ViewBasePage<DefaultViewPresenter>
				    , IDefaultView
    {
        protected void Something_Clicked(object sender, EventArgs eventArgs)
        {
            Presenter.SomeMethod();
        }

        // Here goes implementation of IDefaultView

    }
}

 

The page just inherited form ViewBasePage<DefaultViewPresenter> and all of the plumbing code is gone from the page

Looking much better, isn’t it? 🙂

Presenter

Presenter is even simpler

using Vuscode.Framework.ModelViewPresenter;

namespace Presenters
{
    public class DefaultViewPresenter  : Presenter<IDefaultView>;
    {
        public void SomeMethod()
        {
            if (View.SomeValue>0)
            {
                // do something
            }
        }
    }
}

All presenter had to do is to inherit from Presenter<IDefaultView> in order to get View injected and potential to override OnViewXXX methods

Looking much better, isn’t it? 🙂

What’s next?

Today I showed how to remove code noise from the MVP related types and also set up the foundations of two components: Web.Base and Framework. My next blog post would be expanding a bit framework component in order to show how to work with HttpContext related concepts and values without referencing System.Web into presenters

‘till then…

 

Posted on July 27, 2008, in Uncategorized. Bookmark the permalink. 7 Comments.

  1. Great Article. And nice idea to genericize the presenter.
    Thank you!

  2. I’m not a fan of your IPresenter interface, I’m not even sure why you would want a marker for the presenter class and use an interface since presenters will always inherit from Presenter<TView> I don’t see why you would ever actually access anything through the interface so I feel it’s just adding code noise for no value.
    Even if you have some reason for that interface, the fact you have object View is just incomprehensible when you clearly understand how to use generics. Yuck for boxing for no reason.
    Your interface either should be removed or should look like
        public interface IPresenter<TView>
        {  
            TView View { get; set; }  
            void OnViewInitialized();  
            void OnViewLoaded();  
        }  

  3. Chris,
    You need IPresenter interface with View property so you could in ViewBasePage on encapsulated manner inject instance of the view to presenter.
    As for the IPresenter<TView>, I’ve tried that last year and I didn’t know how to rewrite the ViewBasePage to use that IPresenter<TView> without creating terrible generic mess.
    I would be more than happy if you could update the source code attached to this blog post with the generic IPresenter<TView> and email and/or post it as comment on this post. To be honest, I am not even sure it can be done in such a way that has any sense to be used compared to original copy paste scenario from the post beginning.
    Anyhow, let say it is doable…
    Boxing is an awful thing but only when value types are boxed, while boxing reference type is not creating any significant performance overhead. So (while I understand importance of personal code style preferences) I don’t see any real performance problem with my implementation. That fact combined with the fact that KISS design principle is one of the most important design criteria for me made me to pick deliberately explicit interface based solution.
    If I can get external framework API simplicity for the price of having encapsulated reference type boxing in the framework guts, I would always opt in for that compromise and the solution I presented (which result with simple PageA : BasePage<PageAPresenter>,IPageAView  ‘every day scenario’ usage)
    Looking forward to see that code sample 🙂
    Nikola

  4. Absolutely brilliant.  I am new to this pattern, but I love what you are doing with it.  Brilliant.  I would love to see more on MVP in relation to Web UI and how to get data into grids and dropdowns.  I like the passive view concept for portability and skinability.  I am trying to figure out how to populate grids and dropdowns nicely from a presenter without doing the databinding and muddying up the HTML with binding tags and such.

  5. How would you use multiple presenters within any given view using this approach

  6. My only issue here is that ASP.Net page lifecycle will create a new view on every post-back.  Thus, you must deal re-creating the presenter on every click.  I have yet to solve that problem myself.  

  7. This soluction won't work with WinForms because the designer does not allow generics in the definition of the class, like:
    public class MainForm: BaseView<main>

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: