Programming Microsoft ASP.NET 4 - Dino Esposito [8]
In the implementation of the pattern, you start from a base page class and define a strategy to process the request—the page life cycle. In the implementation of the page life cycle, you come up with an interface of virtual methods and events that derived pages will have to override and handle. (See Figure 1-3.)
Figure 1-3. The internal page life cycle exposed to user code via page controller classes.
Derived page classes are known as code-behind classes in ASP.NET jargon. Writing an ASP.NET page ultimately means writing a code-behind class plus adding a description of the user interface you expect for it. The code-behind class is the repository of any logic you need to serve any possible requests that can be originated by the input elements in the page. A code-behind class derives from a system class—the System.Web.UI.Page class.
Taken individually, a code-behind class is simply the “controller” object responsible for processing a given request. In the context of an application, on the other hand, it can lead you to building a small hierarchy of classes, as shown in Figure 1-4.
Figure 1-4. A sample hierarchy of classes.
Your code-behind class can inherit from the system base class or from intermediate classes with a richer behavior. Developers can extend the hierarchy shown in the figure at will. Especially in large applications, you might find it useful to create intermediate page classes to model complex views and to fulfill sophisticated navigation rules. Building a custom hierarchy of page classes means placing custom classes in between the page controller and the actual code-behind class.
The ultimate reason for having a custom hierarchy of pages is to customize the page controller, with the purpose of exposing a tailor-made life cycle to developers. An intermediate class, in fact, will incorporate portions of common application behavior and expose specific new events and overridable methods to developers.
Revisiting the Page Controller Pattern
Today the main focus of Web architectures is more oriented toward the action rather than the concrete result. This is essentially because of a paradigm shift that generalized the use of the Web tool—it’s no longer just a way to get HTML pages but is a lower level producer of data with its own (variable) representation.
To serve the needs of the new Web, you probably don’t need all the thick abstraction layer that purposely was added on top of the Web Forms model ten years ago with the precise goal of simplifying the production of the sole conceivable output—the HTML page.
A framework like ASP.NET MVC—even though it is built on the same runtime environment as ASP.NET Web Forms—will always adhere more closely than ASP.NET Web Forms to the new paradigm. It’s a matter of structure, skeleton, and posture; it’s not a matter of gesture or behavior. However, there’s some room for teams of developers to revisit the Web Forms model and change its posture to achieve benefits in terms of both testability and separation of concerns.
Revisiting the Page Controller pattern today means essentially taking into account design patterns that privilege separation of concerns between involved parts of the system. This probably doesn’t mean that you can rearrange the entire page life cycle—you need a new framework for that similar to ASP.NET MVC—but you can restructure some portions of the page life cycle to isolate portions of code as distinct components that are testable and writable in isolation.
For example, revisiting the Page Controller pattern means applying the Model View Presenter (MVP) pattern to decouple the implementation of the postback mechanism with the subsequent rendering of the view. We’ll get back to this topic in Chapter 15.
In the end, in the second decade of the 2000s ASP.NET Web Forms is approaching an architectural dead end. On one hand, it is recommended that you do not unconsciously ignore newer frameworks (for example, ASP.NET MVC); on the other hand, however, Web Forms is still highly