Tuesday, June 19, 2007

ASP.NET, or more accurately Web Forms, offer us a completely new way to create web pages. We can now work with control just like Windows developers. We even get to use an event driven model. How make best use of this? Below I present a useful pattern that I'm almost always following while working with ASP.NET.

Suppose that you are building a web application with lots of pages and forms for data input. On those forms you typically have input fields in form of TextBoxes, DropDownLists etc. Usually there are also some buttons that allow for invoking actions. Those actions include things like "Add", "Update" or "Cancel".

The standard way to create a form for inputing data would be to use mentioned before standard ASP.NET controls. That is fine. It gives us access to all that ASP.NET Web Forms can offer in terms of Page structure and event model. There is however one issue. In most cases there we will be several pages with the same buttons on them. Take for example the "Cancel", "Add" or "Update" buttons. Almost every time there is a data to be edited, there will be those buttons. If we use the "out of the box" approach, we end up with code similar to the following, on lots of pages:

<asp:Button ID="Add" runat="server" Text="Add" />

At first glance, there is not much wrong with it. If you look closer however, we can see the potential problems. One of the is certainly the Text property.

Why is it a problem? Suppose that now we need to localize the application? In this case, we will have to make a change in many places. Simple technique would be to decorate the Button control with attributes used by the Localization feature of ASP.NET like meta:resourcekey. But still we end up with one major problem: every time a change is required (that cannot be dealt with using Localization, Skins or other built in feature), we have to make it in many places. As we know: change in many places is a BAD PRACTICE.

What if we find out, that our add buttons need to have some special CssClass attribute? What if all our "Cancel" Buttons should have CausesValidation property set to false? Once again: a change is required in many places - which is ... BAD PRACTICE!

For localization, we can add an implicit localization attributes as mentioned above. What about CausesValidation or CssClass properties? Some of them we can try to set using Skin files, but as you will sooner or later discover, theming support in ASP.NET is VERY limited, especially when it comes to localization. You cannot localize skin files, some of the properties are not themeable etc. There are many examples of potential problems but what is a solution? It seams that there has to be a better way.

In my practice I have found that it is usually good not to use the standard controls that come with ASP.NET but rather make new ones that directly inherit from them. Doing so we inherit all the functionality without loosing anything (almost). As an example, take the aforementioned "Cancel" button. If we create a new control like this:

public class CancelButton : Button
{
    protected override void OnInit(EventArgs e)
    {
        Text = "Cancel"; // get value from resource
        CausesValidation = false;
        base.OnInit(e);
    }
}

And on pages, instead of the standard button, use this new control:

<my:CancelButton ID="Add" runat="server" />

In doing we allow ourselves to make changes in one place that will affect the whole application. In this way, without much work, we have gained a lot of flexibility for the future and saved a lot of potential work. If some time in the future, we need to localize the Text property for all Cancel buttons, we can do it in just one place which is a GOOD PRACTICE.

Benefits do not end there! If some day, there is a requirement, that all buttons should now be LinkButtons instead of normal Buttons we can easily do it bu just changing the base class from which our CancelButton inherits and the same technique can be used with other controls too (as long as their public interfaces match at least in naming).

Now the question is if you should always use the inherited controls. As usual, there is no simple answer to that question. There is a cost of having a lots of additional classes in the project if we try to follow this rule. Imagine that just for standard buttons, there will be quite a few: Add, Cancel, Remove, Back, Change, Edit just to mention some of them. For small, fast'n'dirty projects it will of course be a huge overkill (or will it?), but if you know that the project is not a small task, it is, in my opinion, a thing that should be seriously considered.

kick it on DotNetKicks.com