Revisiting the Content of Code-Behind Classes

When code provides predefined functionalities


August 08, 2008
URL:http://www.drdobbs.com/web-development/revisiting-the-content-of-code-behind-cl/210000256


From a developer's perspective, an ASP.NET page is an ASPX markup file plus a C# or Visual Basic .NET class file. The class file contains some code to handle events fired by controls and arrange the expected behavior. The code lives "behind" the page and backs it up by providing some predefined functionalities. Most of this functionality is, however, hidden to developers and has mostly relevance for the framework.

The code-behind class derives from a fixed class -- the System.Web.UI.Page class -- which provides the foundation of the typical page behavior.

What is the kind of code that you expected to place in a code-behind class? Admittedly, given a control named Button1, the following code is not unusual in ASP.NET pages:

void Button1_Click(object sender, EventArgs e)
{
    DataTable table = new DataTable();
    SqlDataAdapter adapter = new SqlDataAdapter(cmd, conn);
    Adapter.Fill(table);
    DataGrid1.DataSource = table;
    DataGrid1.DataBind();
}

First off, functionally speaking this code works just great. There's nothing wrong with that and it is really easy to write and understand too. Nevertheless, it is far from being optimal from a design perspective. Let's dissect the code to see exactly what it is doing.

The code performs two key tasks: It first gets data from the data source and it then displays data.

This simple fact configures two distinct responsibilities:

How can you modify the code in Button1_Click to make it compliant with best practices?

The method need to do just one thing. This can be only the delegation of all of its tasks to another class:

void Button1_Click(object sender, EventArgs e)
{
   dispatcher.Button1Click();
}

The dispatcher variable refers to a Dispatcher class that ultimately is a collection of methods mapped to use-cases. Any event in the user interface that triggers a reaction in the code-behind will have a method in this dispatcher class. You'll likely have one dispatcher class per page:

public class Page_aspx_Dispatcher
{
    IPageAspxView _page;
    public Page_aspx_Dispatcher(IPageAspxView view)
    {
       _page = view
    }
    public void Button1Click()
    {
        MyDataService service = new MyDataService();
        DataTable table = service.GetData();
        UpdateView_Button1Click(table);
    }
} 

The method is split in two blocks of functionality -- getting data and presenting data. Getting data is the task assigned to the UI function. It is accomplished through a "service" class. The word "service" here is as generic and out-of-context as possible. It may certainly refer to a specific technology like WCF; but not necessarily. A "service" is simply a class, either local or remote, either plain or decorated with ad hoc attributes, that executes a task.

The execution of the task brings data in the context of the page. Another method takes the data and updates the user interface.

What about input data for the task? The dispatcher class needs to have some dependency on the page class. However, it is largely acceptable that the class has dependency on some abstraction of the page; not on the implementation of the page. In practice, you implement an interface on the page class that groups all data that the dispatcher needs to see for its own purpose. You pass this reference when you initialize the dispatcher in the page's constructor.

class Page_aspx : Page, IPageAspxView
{
    Page_aspx_Dispatcher _dispatcher;
    public Page_aspx()
    {
        _dispatcher = new Page_aspx_Dispatcher(this);
    }
    :
}

The dispatcher has access to properties on the page class that may need updates after an event. An example is the Text property of a text box or perhaps the DataSource of a DataGrid. These properties are exposed via an interface and updated once the data is ready.

It's definitely a pattern that delivers a much deeper separation of concerns and that doesn't require you to learn a radically different programming model like the ASP.NET MVC framework. It can be seen as a roughly simplified version of Model-View-Presenter; but more than the pattern itself it is important that you apply separation of concerns and gives you classes as few reasons to change as possible.

Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.