Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Using MVP with ASP.NET Web Forms

0.00/5 (No votes)
12 Jun 2013 1  
A quick example of using MVP with ASP.NET Web Forms.

Introduction

Here I am going to give a quick example of using MVP with ASP.NET Web Forms.

Although I have a development history of Web forms and MVC, I have favored MVC in the past few years mainly because it helps separate out the application layers and allows the easier inclusion of unit testing. However my current client has a large collection of ASP.Net Web Forms applications and they have no intention of moving over to MVC. They are interested in unit testing and dependency injection frameworks, so utilising the MVP pattern with web forms was the best path to take.

MVC and MVP

The main difference between MVC and MVP is how views are handled. In MVC it is down to the controller to choose which view is to be sent to the client whereas in MVP there is no real choice the view is managed by a presenter.

Basics of MVP

Using MVP in ASP.Net Web Forms

MVP (Model, View, Presenter)

There are two variants of MVP; Passive View and Supervising Controller. I am going to concentrate on Passive View for this article as that is what I have more experience with and I believe it allows the easier adoption of unit testing although you do end up with a larger solution.

Like more traditional ASP.NET Web Forms applications, you have a main solution with web project within it. But here the web project is a pretty dumb project in regards to business logic. For this example the web project is the View. There can be any number of other projects in the solution, but the main ones are Model (class library), Presenter (class library) and Tests (class library).

It is also acceptable to have a Service project and ViewModel project; but I will not touch on those here.

The key aspect of communication between the View and Presenter is the use of Interfaces.

In this example I am going to create a simple login page which on successful login redirects the user to a secure home page and on failure kicks them back to an error page. Quite simple.

The code behind of an aspx page implements an interface which exists in the Presenter project. This interface exposes properties on the ASPX page like this:

ILoginView.cs
// in Presenter
public interface ILoginView
{
 string FileName { get; set; }
}
Login.aspx
// in code behind of aspx page
public partial class Login : BasePage , ILoginView
{
 public string FileName { get; set; }
public Login()
{
  AuthorizationService = AuthorizationService;
}
// login submit
protected void btnSubmit_Click(object sender, EventArgs e)
{
  var presenter = new LoginPresenter(this, AuthorizationService);
  var userName = txtUserName.Text;
  var password = txtPassword.Text;
  presenter.CheckUser(userName, password);
  Response.Redirect(FileName);
}

Line 14: Creates an new instance of the presenter which knows about the ILoginView and IAuthorizationService interfaces (don’t worry about the authorization service, it sits in the service project).

Line 19: The CheckUser method is called which in turn calls the LookupUser method in the authorization service class. This is where the interaction between Presenter and Model occurs; in practice this service would be separated in to the Service project.

For this to work, we need to be using an IoC (Inversion of Control)/DI (Dependency Injection) framework. I have opted to use Castle.Windsor for this.

public class BasePage : Page
{
  public IAuthorizationService AuthorizationService { get; set; }
    public BasePage()
    {
      var installer = new IocConfigurator();
      var container = installer.BootstrapContainer();
      AuthorizationService = container.Resolve();
    }
}
public class IocConfigurator : IWindsorInstaller
{
   public IWindsorContainer BootstrapContainer()
   {
     return new WindsorContainer().Install(FromAssembly.This());
   }
   public void Install(IWindsorContainer container,
                       IConfigurationStore store)
    {
        container.Register(Component.For().ImplementedBy());
    }
}

I won’t delve into this code too much except to say it basically injects an instance of AuthorizationService whenever it finds IAuthorizationService. This is done via the BasePage class which is inherited by the aspx code behind class.

LoginPresenter.cs
// presenter
private readonly ILoginView _view;
private readonly IAuthorizationService _authorizationService;
public LoginPresenter(ILoginView view, IAuthorizationService authorizationService)
{
   if (view == null)
  {
    throw new ArgumentNullException();
  }
  this._view = view;
  this._authorizationService = authorizationService;
}
public void CheckUser(string userName, string password)
{
  bool isValidUser = _authorizationService.LookupUser(userName, password);
  // valid user
  if (isValidUser)
   {
     _view.FileName = "/Secure/Home.aspx";
   }
// is not valid user
  if (!isValidUser)
   {
     _view.FileName = "Error.aspx";
   }
}

Line 18: If it is a valid user, the properties for the View are set on lines 23 and 29.

Back to Login.aspx line 21: Now the FileName property has been set, the redirect takes the user there.

As you can see there is not much going on in the View; all the logic is left to the Presenter layer to look-up the user. This separation allows the inclusion of dependency injection (a later post) and unit testing.

Simple Unit Test

[Test]
public void is_user_valid_returns_false()
{
  // arrange
  var invalidUserName = "invalid_user";
  var invalidPassword = "invalid_password";
  var mockAuthService = new Mock();
  mockAuthService.Setup(x => 
    x.LookupUser(invalidUserName, invalidPassword)).Returns(false);
  IAuthorizationService authorizationService = mockAuthService.Object;
  var view = new LoginViewStub();
  var presenter = new LoginPresenter(view, authorizationService);
  // act
  presenter.CheckUser(invalidUserName, invalidPassword);
  // assert
  Assert.AreEqual("Error.aspx", view.FileName);
}

Line 13: As you can see here there is a need for a Stub which like the View; implements the same interface.

public class LoginViewStub : ILoginView
{
  public string FileName { get; set; }
}

Because we are using an interface for the authorization service; we can easily mock that in the tests and set the return value. Here I am using the MoQ framework.

So there you have it a very simple introduction to using MVP with Web Forms. I have used this methodology on two large projects and it has given me a new respect for Web Forms.

Happy coding.

References

The post Using MVP with ASP.NET Web Forms appeared first on Don't Believe The Type.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here