Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Web Development

Revisiting the Content of Code-Behind Classes



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:

  • Having in a method (but also in a class) multiple responsibilities is, design-wise, never a thing to be proud of. The Single Responsibility Principle is one of the key principles in software design and states that each class, method, function, in general, any software modules must have only one reason to change.

  • Having just one reason to change in the end means having one main responsibility. Applying this principle widely takes you to simpler and more specialized classes easier to read, understand, and modify without cascading changes and regression.

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.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.