Applying the MVP Pattern in Classic ASP.NET
Maybe you are now working on such a project?
If so, then you most likely came across a complexly interwoven set of events, logic, and validations within page classes.
This article talks about how you can simplify life on such projects using the same Model-View-Presenter template.
I will assume that you are familiar with the MVC pattern and will not dwell on it in detail in this article.
I will try to correlate MVC with the features that classic ASP.NET provides:
1. Routing - request processing
The folder tree of a site in most cases can serve the same purpose.
2. View and PartialView - data presentation
The Page class and UserControl, respectively, are great for these purposes.
3. Model - data
Classes of models are most likely present in your system in some form.
4. Presenter - glue between data and presentation.
ASP.NET unfortunately does not provide for this type of object.
We are now going to deal with the implementation of the presenter.
The purpose of the presenter is to prepare data for display to the user and process the data entered by him.
The purpose of the presentation is to show data to the user and receive data from the user.
There are different opinions about how smart the presentation and the presenter can be.
Since there is no consensus, I prefer to proceed from the effectiveness of the implementation, which depends on the environment. In this case, from the existing ASP.NET library, which has a wide range of fairly smart controls that I would like to use to the full, since such an opportunity is present.
Finally, proceed to implementation.
We create two classes PageView and UserControlView:
public abstract class PageView: Page where T : class
{
private T _presenter;
public T Presenter
{
get { return _presenter ?? (_presenter = CreatePresenter()); }
}
protected abstract T CreatePresenter();
}
public class UserControlView : UserControl
{
public T Presenter { get; set; }
}
The PageView class is abstract and involves the independent creation of a presenter in a descendant.
The UserControlView class has the only property - Presenter, which is initialized by the parent on which the user element is located.
It is assumed that the page presenter contains the presenters of its custom elements.
An example implementation of a list and its element:
List.aspx
<%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="List.aspx.cs" Inherits="WebApplication1.Client.List" EnableViewState="false" %>
<%@ Register TagPrefix="ctl" TagName="Item" Src="Details.ascx" %>
List.aspx.cs
public partial class List : PageView
{
protected override ListPresenter CreatePresenter()
{
return new ListPresenter();
}
protected override void OnLoad(System.EventArgs e)
{
base.OnLoad(e);
ctlList.DataSource = Presenter.Items;
ctlList.DataBind();
}
}
Details.aspx
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="Details.ascx.cs" Inherits="WebApplication1.Client.Details" %>
Detalis.aspx.cs
public partial class Details : UserControlView
{
protected void OnFirstNameChanged(object sender, System.EventArgs e)
{
Presenter.Model.FirstName = ((TextBox) sender).Text;
}
protected void OnLastNameChanged(object sender, System.EventArgs e)
{
Presenter.Model.LastName = ((TextBox)sender).Text;
}
protected void OnSave(object sender, System.EventArgs e)
{
Presenter.Save();
}
}
By the way, please note, ViewState on pages is turned off.
A complete example can be downloaded here .
Advantages of this approach:
1. The code of the page becomes much simpler
2. You can write unit tests for presenter classes
3. You can use presenters to implement various interfaces (web, win, mobile)
4. You can use it with the noodle code and upgrade the application gradually
I hope my experience will be useful to you.