Products

Solutions

Resources

Partners

Community

About

New Community Website

Ordinarily, you'd be at the right spot, but we've recently launched a brand new community website... For the community, by the community.

Yay... Take Me to the Community!

The Community Blog is a personal opinion of community members and by no means the official standpoint of DNN Corp or DNN Platform. This is a place to express personal thoughts about DNNPlatform, the community and its ecosystem. Do you have useful information that you would like to share with the DNN Community in a featured article or blog? If so, please contact .

The use of the Community Blog is covered by our Community Blog Guidelines - please read before commenting or posting.


Creating Testable Modules - Hello World

At Open Force Europe, this fall, I will be presenting a talk on Creating Testable Modules.  This is part 3 of a series of blogs  where I intent to describe the process as I work my way through developing this talk.  In previous posts, I have introduced some of the concepts including the Model View presenter design pattern.  In this blog I will dig deeper into this pattern by creating a simple Hello World application.  I will be using the Passive View variant of the pattern (see Figure 1).

This blog is cross-posted from my personal blog.

Figure 1 – MVP – Passive View


As can be seen from the diagram, while everything is centered on the Presenter, it is the View that receives the initial request, and it is the View that is instantiated by the WebForms Framework.

Hello World Requirements

Our “Hello World” application is actually a little more than the typical Hello World application.  It has the following requirements.

  1. The application will include a label, a text box to enter text and two buttons – Submit and Reset.
  2. On initially browsing to the page the label will give the user instructions
  3. When the user clicks the Submit button, the label is updated to display “Hello “ and the text the user enters in the text box
  4. When the user clicks the Reset button, the label is reset to display the initial instructions.

These are pretty straightforward requirements, but they should allow us to see how the MVP pattern works.

Figure 2 – The Hello World MVP Web Application Project


You will note that I have followed the convention used in ASP.NET MVC, by creating separate folders for the Models, Presenters and Views.  This is not required, but is just a convenience. 

This particular example is not a DotNetNuke module as it is just designed to demonstrate the basic pattern. 

You will also note that there is an interface for both the View (IView) and the Model (IModel).  While you will almost always see interfaces defined for the View, you will not always see an interface for the Model, but interfaces make the whole system more testable as it allows us to use Mock (fake) versions of the objects when Unit Testing.

The Model

We will start by looking at the Model.  Listing 1 shows the IModel Interface.  Its pretty basic, one property - Text - to hold the text to display.

Listing 1 – IModel Interface
   1:  interface IModel
   2:  {
   3:      string Text { get; set; }
   4:  }

Listing 2 shows the Model Class.  Again, pretty basic, the single property – Text – backed by a private member text.

Listing 2 – Model Class
   1:  public class Model : IModel
   2:  {
   3:      private string text;
   4:   
   5:      public string Text
   6:      {
   7:          get { return text; }
   8:          set { text = value; }
   9:      }
  10:  }

In fact, in order to meet our requirements we don’t actually need a Model class as we don’t need to persist the text entered by the user.

The View

We are using the Passive View variant of the MVP pattern, so our View is pretty dumb.  Listing 3 shows the IView Interface.

Listing 3 – IView Interface
   1:  public interface IView
   2:  {
   3:      string Label { set; }
   4:      string Text { get; }
   5:  }

The interface defines the basic elements of the View that the Presenter will need to interact with – ie the Presenter will need to read the Text property and set the Label property.  In addition to implementing this simple interface, the actual HelloWorldView concrete class will need to manage the events raised by the Submit and Reset buttons.

Lets first look at the ascx file for the concrete View (Listing 4).  The ascx file is fairly straightforward.  It has a Label, a TextBox and two Buttons as specified in the requirements.

Listing 4 – HelloWorldView.ascx
   1:  <h1>Hello World Exampleh1>
   2:  <h2><asp:Label ID="lbl" runat="server" />h2>
   3:  <asp:TextBox ID="txt" runat="server" style="width:400px" />
   4:  <br /><br />
   5:  <asp:Button ID="submit" runat="server" Text="Submit" OnClick="submit_Click" />  
   6:  <asp:Button ID="reset" runat="server" Text="Reset" OnClick="reset_Click" />

In the code behind file for the concrete View (Listing 5), we see that the user control inherits from the UserControl class and implements the IView interface. 

Listing 5 – HelloWorldView.ascx.cs
   1:  public partial class HelloWorldView : System.Web.UI.UserControl, IView
   2:  {
   3:      protected Presenter presenter;
   4:   
   5:      public HelloWorldView()
   6:      {
   7:          //Instantiate associated Presenter
   8:          presenter = new Presenter(this);
   9:      }
  10:   
  11:      public string Label
  12:      {
  13:          set { lbl.Text = value; }
  14:      }
  15:   
  16:      public string Text
  17:      {
  18:          get { return txt.Text; }
  19:      }
  20:   
  21:      protected override void OnLoad(EventArgs e)
  22:      {
  23:          //Call base class to ensure events are fired
  24:          base.OnLoad(e);
  25:   
  26:          //Run the OnViewLoaded method of the Presenter
  27:          presenter.OnViewLoaded(Page.IsPostBack);
  28:      }
  29:   
  30:      protected void submit_Click(object sender, EventArgs e)
  31:      {
  32:          presenter.Update();
  33:      }
  34:   
  35:      protected void reset_Click(object sender, EventArgs e)
  36:      {
  37:          presenter.Reset();
  38:      }
  39:  }

The two properties, Text and Label, specified in the interface encapsulate the Text properties of the Textbox and Label controls.  The control has a private variable of type Presenter, which is instantiated in the control’s constructor, passing itself as a constructor parameter so the Presenter can reference the View’s public properties.  The View’s event handlers (submit_Click and reset_Click) and lifecycle methods (OnLoad) call methods on this Presenter instance.

The Presenter

The Presenter is the hub of this pattern, passing information back and forth between the View and the Model.  It contains private references to both the View and the Model (defined as being of types IView and IModel).  As was seen above, the actual View is passed to the constructor of the Presenter, when it is instantiated in the Constructor of the View.  In order to satisfy the initiial requirements the Model variable is also instantiated in the Presenters constructor and its value is set to the introduction text (IntroText).

Listing 6 – The Presenter
   1:  public class Presenter
   2:  {
   3:      private IView view;
   4:      private IModel model;
   5:   
   6:      private string IntroText = "Enter your name and click the Submit Button";
   7:   
   8:      public Presenter(IView view)
   9:      {
  10:          //set private view variable
  11:          this.view = view;
  12:   
  13:          //Instantiate Model
  14:          model = new Model();
  15:          model.Text = IntroText;
  16:      }
  17:   
  18:      private void DisplayText()
  19:      {
  20:          //Update View
  21:          if (model.Text == IntroText)
  22:              view.Label = model.Text;
  23:          else
  24:              view.Label = String.Concat("Hello - ", model.Text);
  25:      }
  26:   
  27:      public void OnViewLoaded(bool isPostBack)
  28:      {
  29:          if (!isPostBack)
  30:              DisplayText();
  31:      }
  32:   
  33:      public void Reset()
  34:      {
  35:          //Reset Model
  36:          model.Text = IntroText;
  37:   
  38:          //Update View
  39:          DisplayText();
  40:      }
  41:   
  42:      public void Update()
  43:      {
  44:          //Update Model
  45:          model.Text = view.Text;
  46:   
  47:          //Update View
  48:          DisplayText();
  49:      }
  50:  }

The OnViewLoaded, Reset and Update methods which are called by the Views lifecycle methods and event handlers, handle all the communication between the Model and the View and vice versa.

As was mentioned above the Model is not really necessary in this simple example – it is just used to store the value of the text entered by the user, and in this scenario, this could be handled by a private variable in the Presenter class itself.

This was a simple demonstration of the MVP – Passive View pattern.  In the next blog I will develop some tests for it.

Comments

Comment Form

Only registered users may post comments.

NewsArchives


Aderson Oliveira (22)
Alec Whittington (11)
Alessandra Daniels (3)
Alex Shirley (10)
Andrew Hoefling (3)
Andrew Nurse (30)
Andy Tryba (1)
Anthony Glenwright (5)
Antonio Chagoury (28)
Ash Prasad (37)
Ben Schmidt (1)
Benjamin Hermann (25)
Benoit Sarton (9)
Beth Firebaugh (12)
Bill Walker (36)
Bob Kruger (5)
Bogdan Litescu (1)
Brian Dukes (2)
Brice Snow (1)
Bruce Chapman (20)
Bryan Andrews (1)
cathal connolly (55)
Charles Nurse (163)
Chris Hammond (213)
Chris Paterra (55)
Clint Patterson (108)
Cuong Dang (21)
Daniel Bartholomew (2)
Daniel Mettler (181)
Daniel Valadas (48)
Dave Buckner (2)
David Poindexter (12)
David Rodriguez (3)
Dennis Shiao (1)
Doug Howell (11)
Erik van Ballegoij (30)
Ernst Peter Tamminga (80)
Francisco Perez Andres (17)
Geoff Barlow (12)
George Alatrash (12)
Gifford Watkins (3)
Gilles Le Pigocher (3)
Ian Robinson (7)
Israel Martinez (17)
Jan Blomquist (2)
Jan Jonas (3)
Jaspreet Bhatia (1)
Jenni Merrifield (6)
Joe Brinkman (274)
John Mitchell (1)
Jon Henning (14)
Jonathan Sheely (4)
Jordan Coopersmith (1)
Joseph Craig (2)
Kan Ma (1)
Keivan Beigi (3)
Kelly Ford (4)
Ken Grierson (10)
Kevin Schreiner (6)
Leigh Pointer (31)
Lorraine Young (60)
Malik Khan (1)
Matt Rutledge (2)
Matthias Schlomann (16)
Mauricio Márquez (5)
Michael Doxsey (7)
Michael Tobisch (3)
Michael Washington (202)
Miguel Gatmaytan (3)
Mike Horton (19)
Mitchel Sellers (40)
Nathan Rover (3)
Navin V Nagiah (14)
Néstor Sánchez (31)
Nik Kalyani (14)
Oliver Hine (1)
Patricio F. Salinas (1)
Patrick Ryan (1)
Peter Donker (54)
Philip Beadle (135)
Philipp Becker (4)
Richard Dumas (22)
Robert J Collins (5)
Roger Selwyn (8)
Ruben Lopez (1)
Ryan Martinez (1)
Sacha Trauwaen (1)
Salar Golestanian (4)
Sanjay Mehrotra (9)
Scott McCulloch (1)
Scott Schlesier (11)
Scott Wilkinson (3)
Scott Willhite (97)
Sebastian Leupold (80)
Shaun Walker (237)
Shawn Mehaffie (17)
Stefan Cullmann (12)
Stefan Kamphuis (12)
Steve Fabian (31)
Steven Fisher (1)
Tony Henrich (3)
Torsten Weggen (3)
Tycho de Waard (4)
Vicenç Masanas (27)
Vincent Nguyen (3)
Vitaly Kozadayev (6)
Will Morgenweck (40)
Will Strohl (180)
William Severance (5)
What is Liquid Content?
Find Out
What is Liquid Content?
Find Out
What is Liquid Content?
Find Out