转至繁体中文版     | 网站首页 | 图文教程 | 资源下载 | 站长博客 | 图片素材 | 武汉seo | 武汉网站优化 | 
最新公告:     敏韬网|教学资源学习资料永久免费分享站!  [mintao  2008年9月2日]        
您现在的位置: 学习笔记 >> 图文教程 >> 站长学院 >> Web开发 >> 正文
ASP.NET下的Page Controller以及Template Method         ★★★★

ASP.NET下的Page Controller以及Template Method

作者:闵涛 文章来源:闵涛的学习笔记 点击数:1424 更新时间:2009/4/23 10:43:40
 您要在 ASP.NET 中构建 Web 应用程序,您希望通过使用内置的 Page Controller(页面控制器)来利用 ASP.NET 的事件驱动特性。

实现策略

默认情况下,Page Controller 模式中所描述的概念是在 ASP.NET 中实现的。ASP.NET 页面框架实现这些概念所采取的方式使得在客户端上捕获事件、将其传输到服务器并调用适当方法这一系列操作的基本机制是自动进行的,并且对实现者来说是不可见的。页面控制器是可扩展的,因为它会在生命周期的特定点上公开各种事件(请参阅此模式后面的"页面生命周期"),因此,与应用程序具体相关的操作可以在适当的时候运行。

例如,假定用户正在与包含一个按钮服务器控件的 Web 窗体页进行交互(请参阅此模式后面的"简单页面示例")。当用户单击按钮控件时,一个事件将作为 HTTP 投递内容传送到服务器,在那里,ASP.NET 页面框架会解释投递的信息,并将引发的事件与适当的事件处理程序相关联。框架自动调用该按钮的适当事件处理程序,作为框架的正常处理的一部分。因此,您不再需要实现此功能。此外,您还可以使用内置控制器,或者,您可以用自己自定义的控制器来代替内置控制器(请参阅 Front Controller)。

页面生命周期

下面按发生顺序列出了页面生命周期中最常见的各个阶段。其中还包括引发的特定事件,以及处理请求时在各个阶段可能执行的一些典型操作:

  • ASP.NET 页面框架初始化(事件:Init)。这是生命周期的第一个步骤,该步骤将初始化 ASP.NET 运行库以便为响应请求做好准备。

  • 用户代码初始化(事件:Load)。您应该执行与应用程序具体相关的常见任务,例如,当页面控制器引发 Load 事件时打开数据库连接。您可以假设:引发 Load 事件后,服务器控件已创建并完成初始化、状态已还原并且窗体控件反映了客户端的更改。 [Reilly02]

  • 与应用程序相关的事件处理。在此阶段,您应该执行与应用程序相关的处理,以响应控制器引发的事件。 .

  • 清理(事件:Unload)。该页面已完成生成,现在可以丢弃。您应该关闭 Load 事件打开的任何数据库连接,丢弃任何不再需要的对象。在连接对象被作为垃圾回收后,Microsoft?.NET Framework 将自动关闭数据库连接。不过,您对何时进行垃圾回收没有任何控制权。因此,显式关闭数据库连接以充分利用数据库连接池是一个很好的做法。

    注意:还有几个页面处理阶段没有在这里列出。不过,这些阶段不用于大多数页面处理情况。

    简单页面示例

    第一个示例是一个简单页面,它接受来自用户的输入,然后在屏幕上显示该输入。该示例说明了 ASP.NET 用于实现服务器控件的事件驱动模型。

    图 1: 简单页面

    当用户键入他或她的名字、然后单击"Click Here"按钮后,键入的名字将直接出现在按钮下面,如图 2 所示。

    图 2: 显示用户输入的简单页面

    在 ASP.NET 网页中,用户界面编程分为两个不同的部分:可视组件(或视图)和结合了模型和控制器的逻辑。这种划分将页面的可视部分(视图)同与页面交互的、页面后面的代码(模型和控制器)分离开来。

    可视元素称为 Web 窗体页。该页面由包含静态 HTML 服务器控件或 ASP.NET 服务器控件(或同时包含这两种控件)的文件构成。在此示例中,Web 窗体页名为 SimplePage.aspx,它由以下代码组成:

     
    
    <%@ Page language="c#" Codebehind="SimplePage.aspx.cs" AutoEventWireup="false" Inherits="SimplePage" %>
    <HTML>
       <body>
          <form id="Form1" runat="server">
             Name:<asp:textbox id="name" runat="server" />
             <p />
             <asp:button id="MyButton" text="Click Here" OnClick="SubmitBtn_Click" runat="server" />
             <p />
             <span id="mySpan" runat="server"></span>
          </form>
       </body>
    </HTML>
     

    Web 窗体页的逻辑由为了与窗体进行交互而创建的代码构成。编程逻辑放在一个与用户界面文件分离的文件中。此文件被称为"代码隐藏"文件,文件名是 SimplePage.aspx.cs:

     
    
    using System;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.HtmlControls;
    
    public class SimplePage : System.Web.UI.Page
    {
       protected System.Web.UI.WebControls.TextBox name;
       protected System.Web.UI.WebControls.Button MyButton;
       protected System.Web.UI.HtmlControls.HtmlGenericControl mySpan;
    
       public void SubmitBtn_Click(Object sender, EventArgs e) 
       {
          mySpan.InnerHtml = "Hello, " + name.Text + "."; 
       }
    }
     

    此代码的用途是通知页面控制器:当用户单击按钮后,将向服务器发送一个请求,并执行 SubmitBtn_Click 函数。

    此实现显示了连接到控制器所提供的事件是多么简单。它还说明,用这种方式编写的代码更易于理解,因为应用程序逻辑没有与管理事件调度的低级代码结合起来。

    公用外观示例

    下面的示例使用页面控制器的典型实现策略来提供显示动态内容的横幅,该横幅在应用程序的每一页上显示已验证的用户的电子邮件地址(该地址是从数据库检索的)。

    站点内的所有页面对象所继承的基类中包含了公用实现。图 3 显示了站点中的一个网页。

    图 3: 显示动态内容的横幅

    站点中的各个页面负责呈现自己的内容,而基类则负责呈现头信息。因为各个页面是从基类继承的,所以它们都具有相同的功能。

    此实现使用了称为 Template Method的设计模式。该模式在一个操作中定义了一个算法的框架,而将一些步骤交给子类完成。Template Method 允许子类重新定义算法的某些步骤,而不必更改该算法的结构。 [Gamma95]

    Template Method 应用于此问题需要将公用代码从各个页面移到一个基类中。这样可以确保公用代码放在一个地方,并且很容易维护。在此示例中,基类名为 BasePage 并负责将 Page_Load 方法连接到 Load 事件。与 BasePage 相关的工作(即从数据库检索用户的电子邮件地址和设置站点名)完成后,Page_Load 函数将调用名为 PageLoadEvent 的方法。子类实现 PageLoadEvent,以执行它们自己的特定 Load 功能。图 4 显示了此解决方案的结构。

    图 4: 代码隐藏页面实现的结构

    请求网页时,ASP.NET 运行库会触发 Load 事件,该事件再调用 BasePage Page_Load 方法。BasePage 方法检索所需数据,然后对所请求的特定页面调用 PageLoadEvent,以执行任何与页面相关的所需加载。图 5 显示了页面请求序列。

    图 5: 页面请求序列

    通过以这种方式实现公用功能,页面不必设置头信息,并且还可以很容易地进行整个站点的更改。如果头信息呈现和初始化代码不包含在一个文件中,则必须对包含与头信息有关的代码的所有文件进行更改。

    BasePage.cs

    基类代码实现了以下功能:

    • 将 Load 事件连接到 Page_Load 方法,以便进行与请求具体相关的初始化。
    • 从请求上下文检索已验证的用户的名字,并使用 DatabaseGateway 类在数据库中查找该用户的记录。该代码将 eMail 标签分配给用户的电子邮件地址。
    • 将站点名分配给 siteName 标签。
    • 调用 PageLoadEvent 方法,可以由派生类实现该方法以进行任何与页面相关的加载。

    注意:最好将 BasePage 类定义为抽象类,因为这样可以强制实现者提供 PageLoadEvent 的实现。不过,在 Microsoft Visual Studio® .NET 中,不可能将此基类定义为抽象类。相反,该类提供可由派生类覆盖的默认实现。

     
    
    using System;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    public class BasePage : Page
    {
       protected Label eMail;
       protected Label siteName;
    
       virtual protected void PageLoadEvent(object sender, System.EventArgs e)
       {}
       
       protected void Page_Load(object sender, System.EventArgs e)
       {
             if(!IsPostBack)
             {
                   string name = Context.User.Identity.Name;
    
                   eMail.Text = DatabaseGateway.RetrieveAddress(name);
                   siteName.Text = "Micro-site";
    
                   PageLoadEvent(sender, e);
             }
       }
    
    
       #region Web Form Designer generated code
       override protected void OnInit(EventArgs e)
       {
          //
          //
          // CODEGEN: 此调用是 ASP.NET Web 窗体设计器所必需的。
             //
             InitializeComponent();
             base.OnInit(e);
       }
             
       /// <summary>
       /// 设计器支持所必需的方法 - 不要使用代码编辑器修改
       /// 此方法的内容。
       /// </summary>
       private void InitializeComponent()
       {    
             this.Load += new System.EventHandler(this.Page_Load);
    
       }
       #endregion
    }
    
     

    BasePage.inc

    您不仅必须为页面后面的逻辑代码提供公用基类,而且还必须提供用来保存视图或 UI 的呈现代码的公用文件。该代码包括在每个 .aspx 页面中。此 HTML 文件不是为了用于进行独立显示。通过使用公用文件,您可以在一个地方进行更改,并将这些更改传播到包括该文件的所有网页。下面的示例代码显示了此示例的公用文件,文件名为 BasePage.inc:

     
    
    <table width="100%" cellspacing="0" cellpadding="0">
       <tr>
          <td align="right" bgcolor="#9c0001" cellspacing="0" cellpadding="0" width="100%" height="20">
             <font size="2" color="#ffffff">欢迎:
             <asp:Label id="eMail" runat="server">username</asp:Label>&nbsp; </font>
          </td>
       </tr>
       <tr>
          <td align="right" width="100%" bgcolor="#d3c9c7" height="70">
             <font size="6" color="#ffffff">
             <asp:Label id="siteName" Runat="server">Micro-site Banner</asp:Label>&nbsp; </font>
          </td>
       </tr>
    </table>
    
     

    DatabaseGateway.cs

    该类封装了这些页面对数据库的所有访问。这是 Table Data Gateway [Fowler03] 的一个例子,它提供了此应用程序中的页面的模型代码。

    using System;
    using System.Collections;
    using System.Data;
    using System.Data.SqlClient;
    
    public class DatabaseGateway
    {
       public static string RetrieveAddress(string name)
       {
             String address = null;
    
             String selectCmd = 
                   String.Format("select * from webuser where (id = ''''{0}'''')",
                   name);
    
             SqlConnection myConnection = 
                   new SqlConnection("server=(local);database=webusers;Trusted_Connection=yes");
             SqlDataAdapter myCommand = new SqlDataAdapter(selectCmd, myConnection);
    
             DataSet ds = new DataSet();
             myCommand.Fill(ds,"webuser");
             if(ds.Tables["webuser"].Rows.Count == 1)
             {
                   DataRow row = ds.Tables["webuser"].Rows[0];
                   address = row["address"].ToString();
             }
    
             return address;
       }
    }
     
     

    Page1.aspx

    下面是如何在页面中使用公用功能的示例:

     
     
    <%@ Page language="c#" Codebehind="Page1.aspx.cs" AutoEventWireup="false" Inherits="Page1" %>
    <HTML>
       <HEAD>
          <title>Page-1</title>
       </HEAD>
       <body>
          <!-- #include virtual="BasePage.inc" -->
          <form id="Page1" method="post" runat="server">
             <h1>Page:
                <asp:label id="pageNumber" Runat="server">NN</asp:label></h1>
          </form>
       </body>
    </HTML>
     

    该文件中的以下指令用于加载头信息的公用 HTML:

     
    
    <!-- #include virtual="BasePage.inc" -->
     

    Page1.aspx.cs

    代码隐藏类必须从 BasePage 类继承,然后实现 PageLoadEvent 方法来进行任何与页面具体相关的加载。在此示例中,与页面具体相关的活动是将数字 1 分配给 pageNumber 标签。

     
    
    using System;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    public class Page1 : BasePage
    {
       protected System.Web.UI.WebControls.Label pageNumber;
    
       protected override void PageLoadEvent(object sender, System.EventArgs e)
       {
          pageNumber.Text = "1";
       }
    }
     

    测试考虑事项

    对 ASP.NET 运行库的依赖性使实现的测试变得很困难。不可能对从 System.Web.UI.Page 或环境中包含的其他各种类继承而来的类进行实例化。这样就不可能对应用程序的各个部分单独进行单元测试。自动测试此实现的唯一方法是,生成 HTTP 请求,然后检索 HTTP 响应,确定响应是否正确。此方法容易产生错误,因为您是将响应的文本与预期的文本进行比较。

    结果上下文

    [1] [2]  下一页


    [C语言系列]NET 中C#的switch语句的语法  [系统软件]托拽Explore中的文件到VB.net的窗口
    [系统软件]Boost库在XP+Visual C++.net中的安装  [常用软件]新配色面板:Paint.Net3.0RC1官方下载
    [常用软件]用内建的“Net Meeting”聊天  [VB.NET程序]Henry的VB.NET之旅(三)—共享成员
    [VB.NET程序]Henry的VB.NET之旅(二)—构造与析构  [VB.NET程序]Henry的VB.NET之旅(一)—失踪的窗体
    [VB.NET程序]在托盘上显示Balloon Tooltip(VB.NET)  [VB.NET程序]Henry手记-VB.NET中动态加载Treeview节点(二)
  • 教程录入:mintao    责任编辑:mintao 
  • 上一篇教程:

  • 下一篇教程:
  • 【字体: 】【发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
      注:本站部分文章源于互联网,版权归原作者所有!如有侵权,请原作者与本站联系,本站将立即删除! 本站文章除特别注明外均可转载,但需注明出处! [MinTao学以致用网]
      网友评论:(只显示最新10条。评论内容只代表网友观点,与本站立场无关!)

    同类栏目
    · Web开发  · 网页制作
    · 平面设计  · 网站运营
    · 网站推广  · 搜索优化
    · 建站心得  · 站长故事
    · 互联动态
    更多内容
    热门推荐 更多内容
  • 没有教程
  • 赞助链接
    更多内容
    闵涛博文 更多关于武汉SEO的内容
    500 - 内部服务器错误。

    500 - 内部服务器错误。

    您查找的资源存在问题,因而无法显示。

    | 设为首页 |加入收藏 | 联系站长 | 友情链接 | 版权申明 | 广告服务
    MinTao学以致用网

    Copyright @ 2007-2012 敏韬网(敏而好学,文韬武略--MinTao.Net)(学习笔记) Inc All Rights Reserved.
    闵涛 投放广告、内容合作请Q我! E_mail:admin@mintao.net(欢迎提供学习资源)

    站长:MinTao ICP备案号:鄂ICP备11006601号-18

    闵涛站盟:医药大全-武穴网A打造BCD……
    咸宁网络警察报警平台