This article goes through different approaches to create enterprise web applications. I outline possible architecture and explain why following MVC II, Front controller and Application controller (which I refer as simply MVC through the article) design patterns will give you the best return on investment (ROI), in terms of application maintenance and usage of application blocks. To make application development that follows MVC II more easy, developers might an adopt existing framework that will do most of MVC II implementations. Such a framework will leave programmers to handle just with application logic and data. I'll end up with NWAF and why using it is the best choice for your application MVC II infrastructure.
Most of the web applications that I've seen are usually made from a web page that holds code for handling page visualization, application logic, and getting or setting data from variety data storage (figure A).
While this might be the fastest way to develop small applications, it is certainly not the case for larger systems and definitely won't help developers to maintain such applications on a time scale.
Writing a code that handles all application aspects on forms produces several problems:
- It's hard to use components of code that you wrote for your systems from other applications that you, or others in your organization, might develop in the future. Wouldn’t it be better to separate application logic code or database access code into different classes / assemblies? By doing so, we can create libraries of classes, from which we will be able to benefit later on in other projects.
- Changes in databases, for example, demand scanning of all pages and finding where those database changes take place. Only then can we go through all pages and fix our code to make them compatible with database changes. If database access code is in separate classes / assemblies, we will only need to amend them once.
- While developing large scale applications, many tasks that we need to write will be retrieved from different pages. It will be much easier to develop and maintain them, if we separate the business logic and data access from application pages.
Those reasons (amongst others) pushed some of us to develop applications in layer architecture. Layer architecture is quite simple to understand and adopt. Building layer applications means that your application will be divided into three base layers: the Visual layer, the Business Logic Layer (BLL) and the Data Access Layer (DAL) (Figure B).
Every layer contains classes that deal with one aspect of the application and are gathered in dedicated assemblies. Working with layers helps the developer to know where he can find the application visual aspect code, its business logic code, or the data access code.
Every layer builds upon classes that would implement application demands and object oriented practices to maximize code reuse in the given application or other existing and future applications.
An application that follows layered architecture should be built from pages that handle only visual application aspects. Those pages might have direct calls to DAL classes or indirect ones going through BLL classes (depending on the application design), in order to process application logic and retrieve data back to the pages. Visual layer classes should use returning DAL/BLL data in order to format that data based on application needs and show the formatted data to end users.
The layer architecture which I describe in the above lines is the suggested Microsoft paradigm for creating a System. Does this architecture provide the best solution for creating easily maintained systems? Does this architecture end up with reusable code that can be easily moved around and used by other applications?
Let us see: there are still a couple of points that make it harder on us to reuse application blocks and maintain systems. The most important point is that there is still coupling between pages and BLL/DAL code since the pages call DAL or BLL classes directly. The optimal relation between pages and BLL/DAL classes would allow de-coupling one from another. Working in this manner wouldn’t force any contact between pages and DAL/BLL classes. Therefore, DAL/BLL designers can create classes without thinking which page will call them eventually.
Decoupling does not only stand for calling BLL/DAL classes but also should be applied to data returned from DAL/BLL classes. The page should work against a contract that specifies the data and the format that will be received from DAL/BLL classes. Page shouldn’t be aware neither of the classes that create data against which it should work nor of the results those classes return. From its point of view, the page data has predefined structures that are located in a certain place, and page duty is just to get that data, format it, and eventually show it to users. Following these rules, page developers do not depend on DAL/BLL developers, BLL/DAL operation, or returned data. As a matter of fact, pages, DAL or BLL classes that were developed in such a manner could be used in any system (as long as pages will find the predefined data structure in the agreed place).
Loosely coupled relations should be adapted to relations between application pages as well. Usually, the redirection of pages to other pages is involved with code written on the source page in order to redirect the user to other pages or by using HTML tags (such as
<A>). Hard coded connection between pages causes us, the developers and application administrators, to modify ASPX files or code behind files if and when application flow has to be changed. The optimal solution will be to divide application flow from pages into separate application flow settings. Application flow settings should hold all application flow rules and should be used by the application to decide to which page to navigate. Application flow settings should be in human readable format (XML) to enable people to change application flow without any coding practice. De-coupling pages one from each other and moving application flow to a dedicated application block helps us to solve another issue, which is related to page navigation based on application state. There are cases in which an application navigation decision is based on the current state of the application or even data returned from calls to BLL/DAL classes. Working in layers where pages serve as the entry point into an application (Page controller design pattern), a call will be made to a page, and just as soon as this page calls other layers, a redirection to other pages might take place if needed. If application logic can be called before the processed pipeline reaches the page, it will be easier to handle one point of application flow as well as creating pages that only deal with formatting and displaying data. Such pages can be used in other applications since they are not connected to any other system classes.
The third point is more about enterprise development but I find it suitable for every environment in which numerous programmers/teams are working on several different projects. Usually, in such a scenario, a Uniform development structure is desired, so we could maintain common work practice between developers \ develop teams across the enterprise. Uniform development structure should not become an exclusive bunch of strict rules that define what the desirable development architecture is. Those rules should be enforced by using an Infrastructure that implements those rules. Regardless of the Uniform development structure, enterprises usually supply a set of infrastructure services for applications (such as logging, audit, monitoring, etc.). The best way to provide those services efficiently is by enforcing a strict pipeline of application flow, which will be used to deliver enterprise services to the application.
Both uniform development structure and infrastructure wouldn’t be easily achieved when direct calls to BLL/DAL classes were to be made from the pages.
Obviously, I'm not the first one who recognized this problem and looked for a more practical solution. This effort has been done by a gang of four and the outcome was the well known design pattern – MVC (Model-View-Controller). MVC was designed for client based applications and then adapted to web applications. The basic idea behind MVC is that the application should be split into View (pages), Controller (business logic, the application flow layer) and model (DAL classes and business logic classes). Actually, ASP.NET is a ‘pure’ implementation of MVC. But as I’ve explained, this model is still limited, and in order to overcome its setbacks, MVC model II was set up. Model II explicitly defined de-coupling between a controller that controls incoming requests and pages that are responsible for visualization. To simulate events as they’re used by MVC, we add Command design pattern to represent user request from the client side. As I’ve already mentioned, we will add front controller as well to provide a single point of entrance to applications. Application flow, which we dealt with earlier, will be managed by application controller. And so, to sum it up, front controller will intercept any request for application process. The front controller will extract commands that specify a certain user request. The request will be managed by application controller that actually calls model classes to activate certain application strategies on application domain data model.
Now, we have a model that is much closer to our desired targets. There is a central point that catches incoming user requests (Front controller) and calls BLL classes (application controller) that use DAL and BLL classes (model) to return model data. To separate system logic and model from system pages, data returned from DAL/BLL classes should follow Value Object design pattern. Value object function as classes that were composed from simple types and contains exclusively class getters. Based on the returned Value Object, controllers decide which page to call. Pages only use model data generated in pre-page call step (Value Object).
To identify the type of user request that has arrived into the server, we will add a new notion called Action or Command (I'll use Command from this point on because it’s actually the command design pattern). Commands are strings that stand for a certain action that the user wants to process on server side. Front controller should parse command from incoming request, and by pre-defined mapping, call to certain command that already mapped for incoming request type. Command classes contain calls to controllers; this calls are system sequences, or to be more precise, application controllers (BLL class). BLL class should return VOs (Value Objects) that help Commands to decide which page should be called.
Command definitions exist as XML definition rather then predefined code. Command objects should be created dynamically at run time when a certain command is being called (the same as ASPX pages are working). Extending the command to pre-defined user instructions enables the user to set which page will be called by returning model data (VOs) thus creating a mechanism that could handle application flow. This flow mechanism saves us the need to deal with page flow inside pages and therefore helps us to create loosely coupled pages that can be used in other web applications.
As you probably guessed, one of the drawbacks of MVC II is that a lot of plumbing work is required in order to implement it. Or in other words, you better get a working infrastructure that already implements MVC + Command + Front Controller + Application Controller + Value object. Such an infrastructure will let you deal only with your pages, controllers (BLL), and model (DAL) classes.
Finding the right MVC infrastructure is a difficult task due to the fact that ASP.NET introduces call back, server side controls, ViewState and other services that you might want to use. The problem is that postback hampers pure implementation of MVC II. Java implementation uses Form action to pass command to server side, but .NET, due to Post back, takes control of the Form action and wouldn’t let us use it to pass commands. Another problem is the implementation of front controller. If you want to be committed to MVC II, front controller should be separated from View. That means that default page controller nature of ASP.NET should be changed. The most common way to achieve this separation is to create a dedicated
IHttpHandler to serve as front controller. But unfortunately, using this design harms page default services such as Postback, Viewstate, etc.
The best solution - NWAF
There aren't many implementations of MVC in ASP.NET, and there’s none that can keep ASP.NET features without harming them. Actually, there are two common implementations of MVC. One is Microsoft UIP application block which is an MVC implementation and not an MVC II (especially MVC II in this article context). Moreover, UIP is a very complicated application block to implement. The second option is .NET implementation of Java Maverick. Maverick either implements MVC II without the support of ASP.NET features (that were mentioned above), or implements MVC (Page is page controller and view) with full support of ASP.NET features. Both MVC solutions supply other features such as external application flow management, state management and more.
NWAF is the only MVC II based framework that supports all ASP.NET features. Besides being a pure MVC II implementation, NWAF is built as a generic framework that supports the running of your controller and model code in different isolated levels from ASP.NET worker process. As a framework that enables code running in other processes, NWAF supplies services to objects running in an isolate process. Those services let users create and work with classes transparently if they are running on the same process as ASP.NET or other processes. NWAF extends command to a level of XML declaration that allows the user to decide which controllers will be called, and sets the application flow by returning values or exceptions that are thrown from controllers. On the first call to the server Command XML definition is compiled in run time into assemblies to minimize impact of Commands on the application performance. Besides its rich features, NWAF is built with extensive use of pluggable architecture and stack interceptions that allow a high level of supplementary new user defined services, events and any other need to interfere with NWAF default flow.
To fully support ASP.NET nature, NWAF contains a server side control that lets users to set commands to each and every control event. Besides setting commands to control events, NWAF supports default command setting via hidden HTML Form field or QueryString parameter.
As you probably guessed, NWAF is a framework that supports all those features that I’ve mentioned earlier. NWAF was created according to enterprise needs that we have studied, and therefore would serve as an optimal solution for enterprise usage.
To better understand NWAF and its features, I’ll go briefly through its architecture. The next article will engage more thoroughly with its architecture and design.
To work around postback problems, NWAF uses
IHttpModule in order to intercept incoming requests.
IHttpModule catches all incoming requests regardless of their suffix. Therefore, suffix filtering is activated and allows users to decide which suffix won't participate in the NWAF process.
IHttpModule calls a dispatcher that extracts incoming command by the following order: it extracts the event that causes postback and the existence of default command in HTML Form or that of default command in QueryString. The first command that was found, in that sequence, will be processed by NWAF. After extracting the command name, the Dispatcher checks for a command object in cache. If a command was found in cache, dispatcher will call command’s '
Do' method (as declared in
ICommand interface that each command object must implement). If a command wasn’t found in cache,
CommandFactory will be called to create a new command object by command declarations.
A command call to pre-defined controller is taking place, not before checking if
EventObjects is attached to command in commands XML definitions. If so, NWAF initializes value object from HTML Form collection and passes it to controller. If not, Form collection and QueryString passes as parameters to the calling controllers. The called controller is implemented by using stack interceptors, therefore enabling flexibility to add functionality to NWAF process. Commands call Controller '
Perform' method which is declared in
IController interface must be implemented by every Controller.
After ‘Controllers Perform method’ is being called, user code that has been written inside
Perform method will be processed.
Perform method sequence would generally include callings to domain model classes. Domain model classes return results as
ValueObjects, which are classes that represent model data.
ValueObjects return to command. If it is defined in Commands definitions file, Command passes
ValueObjects as a parameter to another controller, or else stores
HttpContext. Then, by predefined command declaration and by inspecting return values and exceptions returned from controller, the given command can:
- Redirect call to another command.
- Transfer/redirect execution to page.
- Continue with the default pipe line execution.
Eventually, by going through default pipeline or transferring, the page will be executed by default ASP.NET mechanism. Within pre-written code of page events and page control events,
HttpContext should be bound with page controls.
If high isolation is declared in NWAF config file, command call sequence to controller will be changed. First of all, command will call
IsolationController which is a "dummy" class registered in COM+ as a server application (for now).
IsolationController checks if
fa?ade class that holds all calls to command controllers exists. If not,
IsolationController will call
IsolationFactory to create
Fa?ade object and store it. The
Fa?ade will receive calls from
IsolationController and redirect them to the request controller.
Fa?ade calls to controller, which were implemented by using stack interceptors, enable us to add functionality to NWAF more easily.
Controller calls domain model classes by passing
EventObjects, and as a result domain model classes return
ValueObjects. In order to enable the same programming model for developers, whether their code is running in low or high isolation, two classes were added to NWAF. The first class supplies context for each request entering high isolation process and exposes the current session ID as a context property. The second class supplies data storage services to the user and might use DataStorage to store session or application data. DataStorage is a singleton API to data storage. Also, it makes data storage in ASP.NET process or outside of it transparent to the user.
Web Pages should be derived from NWAF base page that supplies property to set default page command. NWAF also presents server side control that lets users to set command to page control events in a easy visual manner.
CommandControl is also responsible for rendering the presentation of user setting that was sent to server on postbacks.
NWAF is a .NET implementation of web application framework based on MVC II. This framework enables faster development of web applications with high level of code usability, application maintenance, and increases capacity to add new services.
NWAF is an open source initiative that could be found here. We are currently seeking other professionals who would be interested to join us in finishing this project. For further information, please contact.
Detailed explanation of how to download and run NWAF can be found here.