This project is read-only.
Features | Tutorial | Documentation | Downloads | Links | F.A.Q. | Glossary | Current Release

Regular MVP in ASP.Net

Ps: For a more user-friendly version of this tutorial go to http://manicprogrammer.com/cs/blogs/heynemann/archive/2007/01/08/304.aspx

Basic MVP Structure - Building a Login Form using MvpPage

Well, let´s walk through the steps on building a login form using NMvp. This task will be comprised of three steps: Mvp Structure, Unit Tests and ASP.Net structure. Let´s start with the Mvp Structure.

Mvp Structure

For the Mvp part of the problem all we have to do is build a contract for the interface to implement and the presenter that will rule the interface.

Let´s start with the contract. Building a contract in NMvp is as simple as implementing an Interface that inherits from IContract.

This is what we´ll do:

/// <summary>
/// The contract for the login form.
/// </summary>
public interface ILoginForm : IContract {
    /// <summary>
    /// The username to be authenticated.
    /// </summary>
    string Username { get;set;}
    /// <summary>
    /// The password to be authenticated.
    /// </summary>
    string Password { get;set;}
    /// <summary>
    /// The authenticate event.
    /// </summary>
    event EventHandler Authenticate;
    /// <summary>
    /// Indicates if the user is authenticated.
    /// </summary>
    bool IsAuthenticated { get;set;}
} 


Well, the interface is pretty self-explanatory, so now we´ll get to the LoginFormPresenter, that inherits from Presenter<ILoginForm>. The reason for the LoginFormPresenter to inherit from a generic presenter with the ILoginForm contract as a parameter is so when you do work inside the presenter and use the view reference it comes to you in the correct type (if you type this.View it´s of ILoginForm type).

The LoginFormPresenter´s code is this:
/// <summary>
/// Class responsible for managing a view that implements ILoginForm.
/// </summary>
public class LoginFormPresenter : Presenter<ILoginForm> {
    /// <summary>
    /// Default constructor.
    /// </summary>
    /// <param name="view">The login form view that this presenter 
    /// should manage.</param>
    public LoginFormPresenter(ILoginForm view) : base(view) { }

    /// <summary>
    /// The method that initializes the LoginForm view.
    /// </summary>
    /// <param name="isFirstCall">Indicates if this is the first call to 
    /// Initialize.</param>
    protected override void InitCore(bool isFirstCall) {
        this.View.Authenticate += delegate(object sender, EventArgs e) {
            this.View.IsAuthenticated = (this.View.Username == "correct" &&
            this.View.Password == "correct");
        };
    }
    
    /// <summary>
    /// The method that loads the LoginForm view.
    /// </summary>
    /// <param name="isFirstCall">Indicates if this is the first call 
    /// to Load.</param>
    protected override void LoadCore(bool isFirstCall) {
        if (isFirstCall) {
            this.View.IsAuthenticated = false;
        }
    }
} 


You can see that in this presenter we subscribe to the View´s Authenticate event in the InitCore method (it´s called in the OnInit event handler in MvpPage), so that when the view raises an Authenticate event our presenter handles it correctly (the logic for authenticating is bogus to keep the sample simple).

In the presenter Load event we see the IsAuthenticated property of the view to false if it´s the first call to it (IsPostBack in ASP.Net).

Well that pretty much covers all the Mvp plumbing to be done. Next we´ll get to the unit test needed to test this presenter.

Unit Testing

Let´s check out the unit testing code for the Login Form:

/// <summary>
/// Unit testing code for testing login form in MVP pattern.
/// </summary>
<TestClass>
public class LoginFormTestWithoutHost {
    private LoginFormPresenter presenter;
    private ILoginForm view;
    
    /// <summary>
    /// Initialization of the Test.
    /// </summary>
    [TestInitialize()]
    public void MyTestInitialize() {
        view = new LoginFormMock();
        presenter = new LoginFormPresenter(view);
        presenter.Init(true);
        presenter.Load(true);
    }

    /// <summary>
    /// Termination of the test.
    /// </summary>
    [TestCleanup()]
    public void MyTestCleanup() {
    }        

    /// <summary>
    /// Tests one login with correct data.
    /// </summary>
    [TestMethod]
    public void TestLoginWithCorrectData() {
        view.Username = defaultRes.CorrectUsernameAndPassword;
        view.Password = defaultRes.CorrectUsernameAndPassword;
        ((LoginFormMock)view).RaiseAuthenticate();

        Assert.AreEqual<bool>(true, view.IsAuthenticated);
    }
}


As you can see the unit testing code is really simple. The part you are probably asking yourself right now is: What in the lord´s name is LoginFormMock? That´s a very good question indeed. This is the mocking class.

Why we need a mocking class? Well that´s really simple. I want to unit test my UI, but I can´t use the Page in the unit test since the unit test assembly doesn´t even reference System.Web. To perform this unit test I must create a much simpler structure than Page but one that still resembles a LoginForm in every possible aspect. That´s what we´ll do with LoginFormMock:

/// <summary>
/// Mock of the ILoginForm model.
/// </summary>
public class LoginFormMock : ILoginForm {
    /// <summary>
    /// Default constructor.
    /// </summary>
    public LoginFormMock() {            
    }

    #region IContract Members
    /// <summary>
    /// Indicates if the Host status is valid.
    /// </summary>
    public bool IsValid {
        get { return true; }
    }

    private bool isReadOnly = false;
    /// <summary>
    /// Indicates if the form is in read only mode.
    /// </summary>
    public bool IsReadOnly {
        get {
            return isReadOnly;
        }
        set {
            isReadOnly = value;
        }
    }
    #endregion
    
    #region ILoginForm Members
    private string username;
    /// <summary>
    /// Username to be authenticated.
    /// </summary>
    public string Username {
        get {
            return username;
        }
        set {                
            username = value;
        }
    }
    
    private string password;
    /// <summary>
    /// Password to be authenticated.
    /// </summary>
    public string Password {
        get {
            return password;
        }
        set {                
            password = value;
        }
    }        
    
    /// <summary>
    /// Authenticate event.
    /// </summary>
    public event EventHandler Authenticate;
    
    /// <summary>
    /// Raises the authenticate event (only needed in Unit Test).
    /// </summary>
    public void RaiseAuthenticate() {
        if (Authenticate != null) {
            Authenticate(this, EventArgs.Empty);
        }
    }

    private bool isAuthenticated;
    /// <summary>
    /// Indicates if the user is authenticated after the Authenticate request.
    /// </summary>
    public bool IsAuthenticated {
        get {
            return isAuthenticated;
        }
        set {                
            isAuthenticated = value;
        }
    }    
    #endregion
}


So now we´ll run the unit test and make sure it´s passing. The last step will be building a MvpPage that implements a login form in ASP.Net.

ASP.Net MvpPage

As you´ll see implementing the login form as a web page could not be simpler. It´s just a matter of inheriting from MvpPage and specifying the fullname of the presenter. This is it and we´re almost done.

Let´s check on the HTML code for the MvpPage:

<%@ Page Language="C#" AutoEventWireup="true" Codebehind="LoginMvpPage.aspx.cs" Inherits="NMvp.Web.Testing.LoginMvpPage"
    PresenterId="NMvp.TestModel.Login.LoginFormPresenter, NMvp.TestModel" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Login Form</title>
</head>
<body>
    <form id="form1" runat="server">
        <div>
            <asp:Label ID="lblUsername" runat="server" Text="Username:"></asp:Label>
            <asp:TextBox ID="txtUsername" runat="server"></asp:TextBox>
            <br />
            <asp:Label ID="lblPassword" runat="server" Text="Password"></asp:Label>
            <asp:TextBox ID="txtPassword" runat="server"></asp:TextBox>
            <br />
            <asp:Button ID="btnAuthenticate" runat="server" OnClick="BtnAuthenticate_Click" Text="Login" />
            <br />
            <asp:Label ID="lblIsAuthenticated" runat="server"></asp:Label>
        </div>
    </form>
</body>
</html> 


You can verify that it´s a rather simple page and that the only trace of Mvp in it is the <%@ Page ...%> property PresenterId. This is the property that we´ll use to specify the fullname of the presenter so that ASP.Net can correctly instantiate it and use it. The fullname corresponds to the complete name (Namespace + PresenterName) added to the assembly name (the dll name minus the .dll).

Let´s have a look at the server code on this page:

public partial class LoginMvpPage : MvpPage, ILoginForm {
    protected void Page_Load(object sender, EventArgs e) {        
    }

    /// <summary>
    /// Authenticates the user.
    /// </summary>
    /// <param name="sender">Default parameter.</param>
    /// <param name="e">Default parameter.</param>
    protected void BtnAuthenticate_Click(object sender, EventArgs e) {
        if (this.Authenticate != null) {
            this.Authenticate(this, EventArgs.Empty);
        }
    }

    #region ILoginForm Members
    /// <summary>
    /// Gets/Sets the username textbox text.
    /// </summary>
    public string Username {
        get {
            return this.txtUsername.Text;
        }
        set {
            this.txtUsername.Text = value;
        }
    }

    /// <summary>
    /// Gets/Sets the password textbox text.
    /// </summary>
    public string Password {
        get {
            return this.txtPassword.Text;
        }
        set {
            this.txtPassword.Text = value;
        }
    }

    /// <summary>
    /// Authenticate event. Raised on login button click.
    /// </summary>
    public event EventHandler Authenticate;

    /// <summary>
    /// Indicates if the user is authenticated. Managed by Viewstate.
    /// </summary>
    public bool IsAuthenticated {
        get {
            return (this.lblIsAuthenticated.Text == "Authenticated");
        }
        set {
            this.lblIsAuthenticated.Text = value ? defaultRes.AuthenticatedCaption : defaultRes.UnauthenticatedCaption;
        }
    }

    #endregion

    #region IContract Members
    /// <summary>
    /// Indicates if the login form is in read only mode.
    /// </summary>
    public bool IsReadOnly {
        get {
            if (ViewState["IsReadOnly"] != null) {
                return Convert.ToBoolean(ViewState["IsReadOnly"], CultureInfo.InvariantCulture);
            }
            else {
                return true;
            }
        }
        set {
            IsReadOnly = value;
        }
    }

    #endregion
}


As you can see for yourself it´s quite simple. It implements the contract mapping it´s properties to the controls properties and that´s pretty much everything you´ll have to do.

If you run that page you´ll get a page with two textboxes, one button and a message that says "Not Authenticated". If you put "correct" in both textboxes and push the button the message will turn to "Authenticated".

Last edited Jan 9, 2007 at 12:38 PM by maethorin, version 4

Comments

Rubens Jan 30, 2007 at 12:03 AM 
This is quite interesting, I was wondering how MVP and the NMVP framework in particular fit in with the "standard" way of doing visual development in Visual Studio - for example, using drag-and-drop to create grids and databinding columns in design mode...does that break the MVP model? Maybe it would be nice to see an example/tutorial on how one would use NMVP with a gridview + objectdatasource...