.NET and me Coding dreams since 1998!

4Nov/0719

Model View Presenter (MVP) design pattern close look – Part 2 – Passive View

What is Model View Presenter?

MVP pattern is one of the major patterns used for extracting business logic outside of UI elements and by that, enabling unit testing the UI without the need for using specific UI based testing tools

If you are new to Model View Presenter pattern at all, you should check the Model View Presenter entry level post which explains the most important concepts of wiring the presenter and view in step by step manner. Once you would chew that, come back to this post and continue reading :)

  As we can see from this diagram:

  • View contains the Presenter instance (view "knows" presenter)
  • Presenter is the only class knowing how to reach to model and retrieve the data needed for performing business logic
  • Presenter talks to the View through the view interface (abstracted representation of the View without UI specific attributes)
  • View doesn't know nothing about the Model

View responsibility is to show the data provided by presenter, and purpose of the presenter is to reach to model, retrieve the needed data, performs required processing and returns the UI prepared data to the view.

In July 2006, two year old Model View Presenter pattern has been retired and two variations from original MVP pattern came up:

  1. Supervising controller - where the view is handling UI operations on his own based upon the DTO sent by presenter
  2. Passive screen -  subject of today's post. I've already blogged about it, but that post was more of L100 type of post where I deliberately melt down presenter and model, so the most important thing presenter - view wire up could be more clear. Today's post would dig deeper into the Passive view and give a couple of additional information's with proper implementation model presenter separation of concerns .

Stage set up

Today's example would deliberately use the same use case, model and view markup as the one  used in previous supervising controller blog post to makes easier understanding distinction between the two flavors of the MVP pattern implementation, so check out that post for the details on how the example stage is set up before continuing.

Here, I'll just summary example set up into:

  1. Use case describes a web page which should provide database user search functionality for a given user name. Web page is presenting first name, last name and collection of user addresses. In case no user is found for a given username, error message should be presented. If user updates first name or last name, those changes has to be persisted.
  2. Model is represented with a type implementing the IUserService interface which defines two methods: string GetUser(string userName) and void SaveUser(User user). Retrieving/Saving of user should be done by using

The page in design mode would look something like this:

image  

Passive (screen) view

Passive view is a type of MVP design pattern based on a concept that the view of interface should be abstracted representation of the view, where view UI elements would be represented with .NET plain data types. In that way, presenter is (on decoupled way) aware of view UI elements so he could set/get values directly from the view, without the need of any DTO being used by view as a way of viewer<->presenter communication. .

The biggest advantage of the passive view is that leaves the view with only a "few lines of code" making it so simple that it doesn't require testing different then taking a quick look on the view code. Presenter is now having absolute control on view behavior so testing the presenter is all we have to do to verify even that the view works ok. Another very important advantage is the one David Hayden likes so much, and that is: it enables active work separation between the UX's and DEV's, because DEV can make the complete view page logic without having a page(view) at all. All he has to do is to code against agreed view interface (page approximation). All UX guy has to do is to implement view interface on the view (which is pretty trivial thing to be done) and after that he has all the freedom to work not caring what DEV does.

From what I learned from UX people I met so far, they want to stay away of code behind as much as possible. With supervising controller MVP implementation the question of ownership of actual page/control code behind (aspx.cs/ascx.cs) is unclear and usually ends having both UX/DEV working on it. With passive view, UX owns aspx and aspx.cs and DEV owns presenter and model. Amen! :)

The disadvantage of empowering the presenter is that it can lead to very complex presenter classes with a lot of things to be tested where some of them ay not be related strictly to business logic.

Anyhow, IMHO passive view extreme testability provides much greater gain than it causes pain with having more complex presenters. When we add to that equation ability of effective team multitasking  enabling

View interface

View interface in passive view flavor of MVP is usually having much more members defined (comparing with supervising controller) because each one of the interface members  represents abstraction of a view UI element. That allow

That's how:

  • labels are represented with string setter-only properties,
  • text boxes with getter/setter strings, 
  • repeaters, data lists, data grids  etc are represented with collections of strings or other plain types
  • check boxes are represented with boolean values
  • option buttons with integer/string (containing the pointer to the selected one)
  • drop down lists/lists  - Dictionary<TKey, TValue>

image

Interface contains next abstract representations:

  • Collection of strings representing a collection of user addresses. (setter only -> read only)
  • First name and last name strings - (getter and setter)
    There is requirement that user should be able to update those two so the presenter cares about the changes 
  • Search criteria - (getter only)
    Presenter is not setting the value of the search criteria text box. It just reads the value user typed in.
  • ShowResultPannel setter only boolean property  which enables presenter to perform explicit action on view (hide/show the result panel)
  • Label showing error messages is abstracted to StatusMessage  (setter only -> read only)  

There are no events in the view interface

There is no event definition as an abstraction of the search button click event, because view would in button click event handler just directly call the public presenter method which should occur when a button click happens.

The downside of that approach is that now view is coupled to ("view knows") the presenter which in theory is not a best practice, but in real world I could see it only causing problems if you plan to use different presenters with the same view. In my personal experience and in general reading the MVP related stuff on the web, I couldn't find anyone speaking about that use case as something from the real world, so I am not therefore concerning this as a viable architecture concern.

What we gain from this approach is that we have now much simpler view-presenter wire up code where there is no need for event publishing in view nor for event subscribing code in presenter. Testability is increased to because it is much simpler to just call public presenter method to trigger that behavior then to trigger it indirectly through simulation of the event occurrence. Take a look   how complex test code for that event evocation could look :)

There are no DTO (data transfer object)

Due to the fact that presenter is indirectly manipulating the view elements and that the view is "dumb", there is no need for using any DTO objects because there is no need for presenter to pass any kind of data to the view, because view doesn't do anything.

View implementation

Presenter wire up

The pattern used for establishing wire up between the view and presenter is dependency injection - constructor type.

The  key concepts of this wire up are:

  • presenter has a constructor accepting parameter of view interface type
  • view implements the view interface
  • view in page load constructs a presenter instance and throw himself to the presenter
  • presenter has a pointer then to the view, but the pointer type is view interface so presenter is not knowing nothing about the UI specific aspects of the view he's been injected
  • view keeps created instance of the pointer in the page field to support presenter method invocation in case of specific UI events

In code that would look like this:

   1: private UserDetailsPresenter _presenter;
   2:  
   3: protected void Page_Load(object sender, EventArgs e)
   4: {
   5:     // injecting the view into the presenter
   6:     _presenter = new UserDetailsPresenter(this);
   7: }

Implementing view interface

The view is a web page implementing the view interface just to perform simple mapping of the view interface members and appropriate view UI elements they represent, something like this:

   1: #region IUserDetailsView Members
   2:  
   3: public IEnumerable<string> Address
   4: {
   5:     set
   6:     {
   7:         AdressesRepeater.DataSource = value;
   8:         AdressesRepeater.DataBind();
   9:     }
  10: }
  11:  
  12: public string FirstName
  13: {
  14:     get { return FirstNameTextBox.Text; }
  15:     set { FirstNameTextBox.Text = value; }
  16: }
  17:  
  18: public string LastName
  19: {
  20:     get { return LastNameTextBox.Text; }
  21:     set { LastNameTextBox.Text = value; }
  22: }
  23:  
  24: public string SearchCriteria
  25: {
  26:     get { return SearchCriteriaTextBox.Text; }
  27: }
  28:  
  29: public bool ShowResultPannel
  30: {
  31:     set { resultPanel.Visible = value; }
  32: }
  33:  
  34: public string StatusMessage
  35: {
  36:     set { ResultLabel.Text = value; }
  37: }
  38: #endregion

In line 7, we see that when presenter .sets the Address property of the view interface that would result with that string collection being used as a data source of a repeater. That's how presenter knows only about the collection string property but indirectly setting it, he works with the UI elements itself without having any knowledge about them.

Properties FirstName and LastName perform wire up of the view interface members to the text property of appropriate textboxes. When presenter set a value for a IUserDetailsView.FirstName he fills the FirstNameTextBox.Text value. When presenter reads the IUserDetailsView.LastName, he reads the LastNameTextBox.Text control property value. All the time, not knowing a thing about text boxes, presenter work with them.

In line 26, Presenter would read the string value of IUserDetailsView.SearchCriteria which would return him the entry user made in SearchCriteriaTextBox control

In line 31, presenter setting the boolean value of IUserDetailsView.ShowResultPannel, hide/show the panel containing the results.

At the end, in line 36, presenter can set the string value of IUserDetailsView.StatusMessage property if he wants to present a error message on the web page

UI specific event handling

As I've previously said, in this example there won't be any event driven code to support view event handling. Instead, view would make a direct call  to presenter, something like this:

   1: protected void OnUserSearchButtonClicked(object sender, EventArgs e)
   2: {
   3:     _presenter.OnUserSearched();
   4: }
   5:  
   6: protected void OnUserSaveButtonClicked(object sender, EventArgs e)
   7: {
   8:     _presenter.OnUserSave();
   9: }

As we can see in line 3 and 5, the view simply calls a presenter method of on a field containing presenter instance and by that simple command, when save button would be clicked, presenter's OnUserSave() method would be called.

Presenter

Class diagram of the presenter looks like this:

image

As we can see from the diagram, presenter has:

  • two public constructors: one accepting the view and service interface and one accepting only the view with poor man dependency injection creation of the default service interface implementation
  • Two public methods containing the logic needed for handling appropriate UI view events.
  • Presenter has also three fields which are holding the presenter pointers to the view and service layers and to  user originally retrieved from service layer

Presenter initialization

All the business logic of controlling,presenting and updating model and interaction with view should be encapsulated in the presenter. In this example Presenter is getting pointer to the view interface and model services through the utilization of constructor type of dependency injection design pattern.

   1: private readonly IUserService _userService;
   2: private readonly IUserDetailsView _view;
   3:  
   4: public UserDetailsPresenter(IUserDetailsView view)
   5:     : this(view, new UserServiceStub())
   6: {
   7: }
   8:  
   9: public UserDetailsPresenter(IUserDetailsView view, IUserService userService)
  10: {
  11:     _view = view;
  12:     _userService = userService;
  13: }

In lines 11 and 12, presenter is storing interface representations of the given view and service. That's how the _view field would be a pointer to a view web page and presenter would working with that field work with a web page not knowing that (I've explained how in view interface implementation section)

Presenter implementing view required logic

We have two methods in presenter which perform certain actions for a view, when view requests them.

We saw that view would in case of button clicked directly call presenter public method which would perform appropriate action

OnUserSave method implementation

   1: public void OnUserSave()
   2: {
   3:     bool isFirstNameChanged = (_originalUser.Name != _view.FirstName);
   4:     bool isLastNameChanged = (_originalUser.Surname != _view.LastName);
   5:     if (isFirstNameChanged || isLastNameChanged)
   6:     {
   7:         _originalUser.Name = _view.FirstName;
   8:         _originalUser.Surname = _view.LastName;
   9:         _userService.SaveUser(_originalUser);
  10:     }
  11: }

In line 3 and 4, we see how presenter checks if the user edited presented user data. Presenter does that by comparing the values of user instance retrieved from a database with appropriate  view interface implementation.

Example: when in line 3 presenter compares originally retrieved user name with _view.FirstName he compares behind the curtain original value with the text of the FirstNameTextBox control because view is implementing the view interface by wiring up view interface members with real controls.

That's how presenter talks with a view through the view interface

OnUserSearch method implementation

   1: public void OnUserSearched()
   2:     {
   3:         _view.ShowResultPanel = false;
   4:         if (string.IsNullOrEmpty(_view.SearchCriteria))
   5:         {
   6:             _view.StatusMessage = "User name can not be null";
   7:             return;
   8:         }
   9:  
  10:         _originalUser = _userService.GetUser(_view.SearchCriteria);
  11:         if (_originalUser == null)
  12:         {
  13:             _view.StatusMessage = String.Format("There's no user found for user name:{0}", _view.SearchCriteria);
  14:             return;
  15:         }
  16:  
  17:         _view.FirstName = _originalUser.Name;
  18:         _view.LastName = _originalUser.Surname;
  19:         _view.Address = MapUserAddress(_originalUser.Addresses);
  20:  
  21:         _view.ShowResultPanel = true;
  22:     }

In line 3, presenter sets a _view.ShowResultPanel=false, which would  result executing of the next page (view) code

public bool ShowResultPannel
{
    set { resultPanel.Visible = value; }
}

which would hide the old search results on the start of the search.

In line 4, presenter checks if user entered any search criteria by accessing text property of the SearchCriteriaTextBox control via view interface SearchCriteria property. In case user didn't enter any search criteria, presenter in line 6 sets a view interface member value which would result with view showing that string on ResultLabel.

In line 10, presenter reaches out to model and retrieves a user for a given search criteria.

In line 11, presenter checks the result of user retrieval and if there are no users retrieved for a given criteria, shows an error message in line 13. 

In lines 17,18,19 presenter sets the view interface members values which result with appropriate UI actions - setting text boxes and repeater data bounding.

At the end, in line 21, presenter shows result panel to the user

Summary

Passive view pattern is a UI design pattern which moves most of the responsibilities from web pages leaving them to do just plain view interface implementation with wiring up interface members with appropriate UI control properties.

That gives all the brains to presenter, which enables TDD approach because presenter is UI technology  agnostic, so we are able to write test methods against it and by testing the presenter we are testing indirectly the page itself.

That and its suitability for decoupled team work makes passive view my favorite  flavor of the MVP/MVC pattern regardless of the downsides  it has

Source code of today's example can be found here:   Passive (screen) view source code

What is next?

Next parts of the MVP saga would try to take a close look on a conceptual differences between the MVC and MVP patterns which would be helpful to know considering all the buzz future Microsoft MVC ASP NET framework gets these days.

I plan to write also about MVP pattern usage in cases of composite pages (pages controlling controls) which would be something very interested because I am fan of controls having their own presenters so it could be quite challengeable on a first encounter handling all this interfaces on a elegant way.

At the end of the MVP post series I would make a detail post about how to test in real world MVP patterns which would be a more advanced and detailed version of the L100 post I wrote already

Quote of the day:
Anything worth doing is worth doing slowly. - Mae West

 

Share this post :

Comments (19) Trackbacks (0)
  1. Source code link is broken…

  2. The download link is fixed

  3. Hi there,

    Nice article. I only have one question about the DTO part in the view. You say that DTO’s are not needed in the view…. I pass DTO’s to a setter in the view for display purposes.. like datagrid1.DataSource = customerDTO. I also let the view return a customer DTO through an implemented getter if needed. What do you think of that? I think it’s very practicle to work like this, but also have mixed feelings about it.

  4. Hi there,

    Nice article. I only have one question about the DTO part in the view. You say that DTO’s are not needed in the view…. I pass DTO’s to a setter in the view for display purposes.. like datagrid1.DataSource = customerDTO. I also let the view return a customer DTO through an implemented getter if needed. What do you think of that? I think it’s very practicle to work like this, but also have mixed feelings about it.

  5. Jeroen,

    Passing the DTO is more of a supervising controller flavor of MVP which is probably more suitable for Web scenarios then the Passive view flavor (more efficient testing)

    In case you haven’t check it out already, take a peek at

    blog.vuscode.com/…/model-view-presenter-mvp-design-pattern-close-look-part-1-passive-view.aspx

    (Url is miss named – it is supervising controller post)

  6. Jeroen,

    Passing the DTO is more of a supervising controller flavor of MVP which is probably more suitable for Web scenarios then the Passive view flavor (more efficient testing)

    In case you haven’t check it out already, take a peek at

    blog.vuscode.com/…/model-view-presenter-mvp-design-pattern-close-look-part-1-passive-view.aspx

    (Url is miss named – it is supervising controller post)

    (I apologize for the CS 2007 problems which you face when tried to leave a comment)

  7. First of all, thank you very much for the excellent posts….they are very helpful. Also, I did want to let you know that the source code link is good but the UserRepository project is missing. It would be nice to see an example of how that’s implemented, too. Still, this information is very helpful. Thanks again!

  8. This does not work! Outside the missing UserRepository project, they way you have this written does not work because the UserDetailsPresenter _presenter object gets re-instantiated on every page load, so you lose the user you were working on!

  9. Im agree with John Coder, it will not work! the presenter can not hold any state

  10. John Coder & duongphuhiep,

    I agree that it won't work because I wrote it more on a general pattern level explanation level then to be "production level".

    Although that was not my intention, I agree that having non working example sucks so I’ll update the code with adding to presenter naïve session caching of view data so the example will work.

    In case you are interested how I approach to this problem in real world, I am doing it using application controller with context persistence services "caching" in encapsulated manner data on server side in order to preserve the data across post backs and multiple pages.

    Application controller is subject of my next  blog post so once I finish it (in case you care) stop by and read it

    Thanks for the tip,

    Nikola

  11. Source code updated.

    Please note that I used quick & dirty solution which required System.Web reference into my Presenter project which is IMHO very smelly thing to do in MVP.

    In case you need to work with HttpContext in Presenter for real world application I recommend you approach I described here

    blog.vuscode.com/…/model-view-presenter-tips-from-trenches-tft-base-types-part-1.aspx

    Once again, if you want stop by in a few day to read application controller based approach I prefer for tackling this in real world MVp implementations

    Nikola

  12. Hi,

    This is a good one. I have a question , Is it possible to use both the patterns in a single application ? I mean can I use Passive for some screens and supervising controller for some screens ?.

    Thank you .

    my email : sunijob@yahoo.com

  13. This is an interesting article Nikola. I like the clear headings, diagrams and supporting code samples. I would recommend getting a native English speaker to proof read your posts. They have great content, but the grammatical errors make it seem unprofessional.

    This is an article about using TDD and a unit testable pattern, but the source code contains zero unit tests.

    If I am to be convinced to use this pattern to help with unit testing, I would expect some clear examples to be given in the article also.

  14. Sunita,

    Everything is possible :)

    I could imagine you using passive view for some “more critical” screens and “supervising controller” for the simple “forms over data” screen

  15. Alex,

    As for my grammar, I am very well aware of that… Unfortunately, you cannot find here in Prague a lot of native English speakers willing to proof read my mumblings. One of my US colleagues offered help and he started editing some of my more recent blog posts (Design for testability series)  but he is busy with his own stuff so this things get slow.

    If anyone reading this is willing to contribute, send me an email on nikola.malovic@google.com

    As for the purpose of article, this was intend to be article about MVP (not TDD). Once you have presenters separated it is quite easy to test them. Check out one of my old blog posts showing how to do that: blog.vuscode.com/…/tdd-rhino-mocks-part-1-introduction.aspx

    It’s a bit outdated (Rhino mock syntax) but it should be still working and illustrative enough

    Thanks for kind words!

    Nikola

  16. Thanks for a great article. It is a great help for a current project.

  17. Great post keep em coming!

  18. ……View contains the Presenter instance (view "knows" presenter) ……

    ==============================================

    Thereis not necessary for this. In my Project Design, I add another Class Called "ViewLoader" to Coordinate the relationship between View and Presenter. So, view "don't knows" presenter at all.

  19. Hi! The link seems to be dead.. can you please update as I'm interested in following this series..

    blog.vuscode.com/…/model-view-presenter-mvp-design-pattern-close-look-part-1-passive-view.aspx

    Thanks


Leave a comment

No trackbacks yet.