Web design mode

Source: Internet
Author: User
Summary

This article introduces some basic methods and key points for improving WebForm program design by applying the Web design pattern under the. NET Framework.

Keywords

Design pattern, ASP. NET, WebForm, MVC, Page Controller, Front Controller, Page Cache

Directory

Introduction
Classic WebForm Architecture
Design Mode
WebForm in MVC Mode
WebForm in Page Controller mode
WebForm in Front Controller mode
WebForm in Page Cache Mode

Introduction

I remember when Microsoft launched ASP. NET, the shocking thing was that developing Web programs was no longer writing traditional Web pages, but building applications. Microsoft called it WebForm. However, two years later, a considerable number of developers are still using the idea of writing script programs to build one WebForm after another without making full use of ASP. this article hopes to inspire readers with some new ideas through examples.
Due to limited space, it is impossible for this article to show readers a WebForm in combination with the design pattern through a complex Web application. However, if it is just a small program, there is no need to use the pattern. For ease of understanding, I hope you can think of it as a small module in a large system (if the code is part of a large system, the usage mode becomes very important ).
All source programs are provided at the end of this article.
Classic WebForm Architecture
First, let's look at a simple application. For database design, for example, the Portal is the parent table of Subject and one-to-many Association is performed through portalId. The program needs to display different Subject lists based on portalId.

According to the general habits of WebForm writing, first drag and drop a DropDownList, A DataGrid, and a Button control on the page:
Interface (webForm. aspx ):
<Form id = "webForm" method = "post" runat = "server">
<Asp: DropDownList id = "dropDownList" runat = "server"> </asp: DropDownList>
<Asp: Button id = "button" runat = "server" Text = "Button"> </asp: Button>
<Asp: DataGrid id = "dataGrid" runat = "server"> </asp: DataGrid>
</Form>

The core code written using the VS. NET code hiding function is as follows:
Post Code (webForm. aspx. cs ):
// Page initialization event
Private void Page_Load (object sender, System. EventArgs e)
{
If (! IsPostBack)
{
String SQL _SELECT_PORTAL = "SELECT * FROM PORTAL ";
// Use using to ensure the database connection is released
// The connection string is stored in the Web. Config file for modification.
Using (SqlConnection conn = new SqlConnection (ConfigurationSettings. etettings ["ConnectionString"])
{
SqlDataAdapter dataAdapter = new SqlDataAdapter (SQL _SELECT_PORTAL, conn );
DataSet dataSet = new DataSet ();
DataAdapter. Fill (dataSet );
// Set the data sources, text fields, and value fields in the drop-down list
DropDownList. DataSource = dataSet;
DropDownList. DataTextField = "portalName ";
DropDownList. DataValueField = "portalId ";
DropDownList. DataBind ();
}
}
}
// Click the Button event
Private void button_Click (object sender, System. EventArgs e)
{
String SQL _SELECT_SUBJECT = "SELECT * FROM SUBJECT WHERE portalId = {0 }";
Using (SqlConnection conn = new SqlConnection (ConfigurationSettings. etettings ["ConnectionString"])
{
// Replace the undetermined character {0} in the SQL statement with the value selected from the drop-down list}
SqlDataAdapter dataAdapter = new SqlDataAdapter (string. Format (SQL _SELECT_SUBJECT, dropDownList. SelectedValue), conn );
DataSet dataSet = new DataSet ();
DataAdapter. Fill (dataSet );
DataGrid. DataSource = dataSet;
DataGrid. DataBind ();
}
}

In the execution result, the program binds the DataGrid according to the value selected in the drop-down list box. A typical WebForm architecture reflects the ASP. NET event-driven idea and achieves the separation of the interface and code. However, you can find several problems:

The code for database operations is repeated. Repeated code is an absolute "Bad taste" in software development. For some reason, when you modify a code, but I forgot to change the same code, leaving the program with bugs.

The post-code completely depends on the interface. The changes in the WebForm lower bound are much greater than those in the data storage structure and access. When the interface changes, you will have to modify the code to adapt to the new page, the entire post code may be overwritten.

The Post Code not only processes user input, but also processes data. If the demand changes, for example, the data processing method needs to be changed, you will almost overwrite the entire post code.
A good design requires every module. Every method focuses only on one thing. Such a structure is clear and easy to modify. After all, the project requirements are constantly changing, "The only thing that remains unchanged is the change itself." A good program must be prepared for the change to avoid "taking the lead". Therefore, we must find a solution to the above problem. Let's take a look at the design pattern.

Design Mode

The design pattern describes a recurring problem and the core solution to the problem. It is a successful architecture, design and implementation solution, and a summary of experience. The concept of design patterns first came from Western architecture, but the most successful case was the "plan" of ancient China ".

WebForm in MVC Mode

The MVC pattern is a basic design pattern used to separate the user interface logic from the business logic. It classifies data processing, interface and user behavior control into Model-View-Controller.
Model: responsible for data acquisition and change of the current application and related business logic
View: displays information.
Controller: Collects input of conversion users.

Both View and Controller depend on the Model, but the Model neither depends on the View nor Controller. This is one of the main advantages of separation, so that the Model can be created and tested separately to facilitate code reuse, view and Controller only need the Model to provide data. They do not know or care about whether the data is stored in SQL Server, Oracle database, or somewhere else.
According to the MVC pattern, the post-code in the above example can be split into Model and Controller, and a dedicated class can be used to process data. The post-code as Controller is only responsible for converting user input, the modified code is as follows:
Model (SQLHelper. cs): encapsulate all database operations.
Private static string SQL _SELECT_PORTAL = "SELECT * FROM PORTAL ";
Private static string SQL _SELECT_SUBJECT = "SELECT * FROM SUBJECT WHERE portalId = {0 }";
Private static string SQL _CONNECTION_STRING = ConfigurationSettings. etettings ["ConnectionString"];
Public static DataSet GetPortal ()
{
Return GetDataSet (SQL _SELECT_PORTAL );
}
Public static DataSet GetSubject (string portalId)
{
Return GetDataSet (string. Format (SQL _SELECT_SUBJECT, portalId ));
}
Public static DataSet GetDataSet (string SQL)
{
Using (SqlConnection conn = new SqlConnection (SQL _CONNECTION_STRING ))
{
SqlDataAdapter dataAdapter = new SqlDataAdapter (SQL, conn );
DataSet dataSet = new DataSet ();
DataAdapter. Fill (dataSet );
Return dataSet;
}
}

Controller (webForm. aspx. cs): responsible for converting user input
Private void Page_Load (object sender, System. EventArgs e)
{
If (! IsPostBack)
{
// Call the Model method to obtain the data source
DropDownList. DataSource = SQLHelper. GetPortal ();
DropDownList. DataTextField = "portalName ";
DropDownList. DataValueField = "portalId ";
DropDownList. DataBind ();
}
}
Private void button_Click (object sender, System. EventArgs e)
{
DataGrid. DataSource = SQLHelper. GetSubject (dropDownList. SelectedValue );
DataGrid. DataBind ();
}

The modified code is very clear, the M-V-C of the division of its system, rewrite any module will not cause changes to other modules, similar to the MFC Doc/View structure. However, if there are many programs with the same structure, we need to make some unified control, such as user identity judgment and unified interface style; or you want the Controller to be more thoroughly separated from the Model, and the Model-Layer Code is not involved in the Controller. At this time, it seems a little powerless to rely on the MVC mode, so please take a look at the following Page Controller mode.

WebForm in Page Controller mode

The MVC mode focuses on the separation between Model and View, but less on the Controller (in the above MVC mode, we only split the Model and Controller, but in WebForm-based applications, the View and Controller are originally separated (displayed in the client browser ), controller is a server-side application. Different user operations may lead to different Controller policies. The application must perform different operations based on the previous page and user-triggered events; in addition, most webforms require a uniform interface style. If this is not handled, duplicate code may be generated. Therefore, it is necessary to divide the Controller more carefully.
The Page Controller mode uses a common Page Base Class Based on the MVC mode to uniformly process Http requests and interface styles,

Traditional webforms generally inherit from the System. Web. UI. Page class, while the implementation idea of Page Controller is that all webforms inherit the custom Page base class,

With the custom page base class, we can receive page requests, extract all relevant data, call all updates to the Model, and forward requests to the View in a unified manner to easily implement a unified page style, the Controller logic derived from it will become simpler and more specific.
The following describes the specific implementation of Page Controller:
Page Controller (BasePage. cs ):
Public class BasePage: System. Web. UI. Page
{
Private string _ title;
Public string Title // page Title, which is specified by the subclass
{
Get
{
Return _ title;
}
Set
{
_ Title = value;
}
}
Public DataSet GetPortalDataSource ()
{
Return SQLHelper. GetPortal ();
}
Public DataSet GetSubjectDataSource (string portalId)
{
Return SQLHelper. GetSubject (portalId );
}
Protected override void Render (HtmlTextWriter writer)
{
Writer. Write ("Base. Render (writer); // output of the subpage
Writer. Write (@ "<a href =" "http://www.asp.net" "> ASP. NET </a> </body> }
}

Now it encapsulates the Model function and implements a unified page title and footer. Subclass only needs to directly call:
The modified Controller (webForm. aspx. cs ):
Public class webForm: BasePage // inherit the Page Base class
{
Private void Page_Load (object sender, System. EventArgs e)
{
Title = "Hello, World! "; // Specify the page title
If (! IsPostBack)
{
DropDownList. DataSource = GetPortalDataSource (); // call the method of the base class
DropDownList. DataTextField = "portalName ";
DropDownList. DataValueField = "portalId ";
DropDownList. DataBind ();
}
}
Private void button_Click (object sender, System. EventArgs e)
{
DataGrid. DataSource = GetSubjectDataSource (dropDownList. SelectedValue );
DataGrid. DataBind ();
}
}

From the above we can see that the BagePage Controller takes over most of the work of the original Controller, making the Controller simpler and easier to modify (for ease of explanation, I did not place the control in the BasePage, but you can do that). However, as the application complexity increases and user requirements change, we can easily divide different page types into different base classes, the inheritance tree is too deep. For example, for a shopping cart program, you need to define the page path. For the Wizard program, the path is dynamic (you do not know your choice beforehand ).
It is not enough to use Page Controller for the above applications. Let's look at the Front Controller mode.

WebForm in Front Controller mode

The implementation of Page Controller requires the creation of code for the public part of the Page in the base class. However, with the passage of time, the demand will change greatly, and sometimes you have to add non-public code, in this way, the base class will keep increasing, and you may create a deeper inheritance hierarchy to delete the conditional logic, which makes it difficult for us to refactor it, therefore, we need to further study Page Controller.
By controlling and transmitting all requests, Front Controller solves the problem of decentralized processing in Page Controller. It consists of two parts: Handler and Command tree. Handler processes all public logic, receives HTTP Post or Get requests and related parameters, selects the correct Command object based on the input parameters, and passes control to the Command object to complete subsequent operations, here we will use the Command mode.
In Command mode, a request can be converted into an object to make a request to an unspecified application object. This object can be stored and passed like other objects, the key to this mode is an abstract Command class, which defines an interface for executing operations. The simplest form is an abstract Execute operation, the specific Command subclass uses the receiver as an instance variable, implements the Execute Operation, and specifies the action taken by the receiver. The receiver has the specific information required to Execute the request.

Because the Front Controller mode is more complex than the preceding two modes, let's take a look at the class diagram of the example:

For more information about Handler principles, refer to MSDN. Let's look at the specific implementation of the Front Controller mode:

First, define in Web. Config:

<〈! -- Specify that the aspx file starting with Dummy is handled by Handler -->
<HttpHandlers>
<Add verb = "*" path = "/WebPatterns/FrontController/Dummy *. aspx" type = "WebPatterns. FrontController. Handler, WebPatterns"/>
</HttpHandlers>
<〈! -- Specify the page ing block named FrontControllerMap and submit it to the UrlMap class for processing. The program will find the corresponding url based on the key as the final execution path, here you can define multiple key-value pairs with URLs -->
<ConfigSections>
<Section name = "FrontControllerMap" type = "WebPatterns. FrontController. UrlMap, WebPatterns"> </section>
</ConfigSections>
<FrontControllerMap>
<Entries>
<Entry key = "/WebPatterns/FrontController/DummyWebForm. aspx" url = "/WebPatterns/FrontController/ActWebForm. aspx"/>
...
</Entries>
</FrontControllerMap>

Modify webForm. aspx. cs:
Private void button_Click (object sender, System. EventArgs e)
{
Response. Redirect ("DummyWebForm. aspx? RequestParm = "+ dropDownList. SelectedValue );
}
When the program is executed here, the ProcessRequest event of the Handler class will be triggered according to the definition in Web. Config:
Handler. cs:
Public class Handler: IHttpHandler
{
Public void ProcessRequest (HttpContext context)
{
Command command = CommandFactory. Make (context. Request. Params );
Command. Execute (context );
}
Public bool IsReusable
{
Get
{
Return true;
}
}
}

It will call the Make method of CommandFactory to process received parameters and return a Command object, then it will call the Execute method of the Command object to submit the processed parameters to the specific processing page.
Public class CommandFactory
{
Public static Command Make (NameValueCollection parms)
{
String requestParm = parms ["requestParm"];
Command command = null;
// Get different Command objects based on input parameters
Switch (requestParm)
{
Case "1 ":
Command = new FirstPortal ();
Break;
Case "2 ":
Command = new SecondPortal ();
Break;
Default:
Command = new FirstPortal ();
Break;
}
Return command;
}
}
Public interface Command
{
Void Execute (HttpContext context );
}
Public abstract class RedirectCommand: Command
{
// Obtain the key and url key-value pairs defined in Web. Config. For details about the UrlMap class, see the code in the downloaded package.
Private UrlMap map = UrlMap. SoleInstance;
Protected abstract void OnExecute (HttpContext context );
Public void Execute (HttpContext context)
{
OnExecute (context );
// Submit the key-value pairs to the specific processing page
String url = String. Format ("{0 }? {1} ", map. Map [context. Request. Url. AbsolutePath], context. Request. Url. Query );
Context. Server. Transfer (url );
}
}
Public class FirstPortal: RedirectCommand
{
Protected override void OnExecute (HttpContext context)
{
// Add portalId to the input parameters for page processing
Context. Items ["portalId"] = "1 ";
}
}
Public class SecondPortal: RedirectCommand
{
Protected override void OnExecute (HttpContext context)
{
Context. Items ["portalId"] = "2 ";
}
}
Finally, in ActWebForm. aspx. cs:
DataGrid. DataSource = GetSubjectDataSource (HttpContext. Current. Items ["portalId"]. ToString ());
DataGrid. DataBind ();

The preceding example shows how to use the Front Controller to centralize and process all requests. It uses CommandFactory to determine the specific operation to be executed, regardless of the method and object to be executed, handler only calls the Execute method of the Command object. You can add additional commands without modifying Handler. It allows users to see the actual page. When users enter a URL, the system will. the config File maps it to a specific URL, which gives programmers more flexibility and obtains an indirect operation layer not included in the Page Controller implementation.
We use the Front Controller mode for quite complex Web applications. It usually needs to replace the built-in Controller of the page with the Custom Handler, in Front Controllrer mode, we do not even need pages. However, because of its complicated implementation, it may cause some troubles to the implementation of business logic.
The above two Controller modes are used to process complicated WebForm applications. Compared with applications that directly process user input, the complexity is greatly improved and the performance is inevitably reduced, for this reason, we finally look at a mode that can greatly improve program performance: Page Cache mode.

WebForm in Page Cache Mode

Almost all webforms face applications with frequent access and few changes. For WebForm visitors, a lot of content is repeated, therefore, we can try to save the WebForm or some of the same content in the server memory for a period of time to speed up the response of the program.
This mode is easy to implement. You only need to add the following to the page:
<%@ OutputCache Duration = "60" VaryByParam = "none" %>,
This indicates that the page will expire after 60 seconds. That is to say, the content of the page is the same for all visitors within 60 seconds, but the response speed is greatly improved, just like static HTML pages.
Maybe you just want to save part of the content instead of saving the whole page, then we will return to SQLHelper. cs in MVC mode, and I made a few changes to it:
Public static DataSet GetPortal ()
{
DataSet dataSet;
If (HttpContext. Current. Cache ["SELECT_PORTAL_CACHE"]! = Null)
{
// If the data exists in the cache, it is taken out directly.
DataSet = (DataSet) HttpContext. Current. Cache ["SELECT_PORTAL_CACHE"];
}
Else
{
// Otherwise, the database is retrieved and inserted into the cache, and the absolute expiration time is set to 3 minutes.
DataSet = GetDataSet (SQL _SELECT_PORTAL );
HttpContext. Current. Cache. Insert ("SELECT_PORTAL_CACHE", dataSet, null, DateTime. Now. AddMinutes (3), TimeSpan. Zero );
}
Return dataSet;
}

Here, SELECT_PORTAL_CACHE is used as the Cache key and the content retrieved from GetDataSet (SQL _SELECT_PORTAL) is used as the Cache value. In this way, in addition to database operations performed by the Program for 1st calls, database operations are not performed during the Cache expiration time, which also greatly improves the response capability of the program.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.