65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 HTTP 模块在 Web 应用程序的所有网页中添加页眉和页脚控件

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.21/5 (21投票s)

2004年6月11日

5分钟阅读

viewsIcon

118971

downloadIcon

1203

使用 HTTP 模块自动为所有 ASP.NET 页面添加页眉和页脚控件。

引言

在开发 Web 应用程序的表示层时,我们通常会为所有网页遵循一个模板结构。该模板通常包含某种公司徽标和导航的页眉部分,以及一些法律信息和联系信息的页脚部分等。这些页眉和页脚部分的 HTML 代码通常在整个站点中是相同的,因此可能需要在每个网页中复制和粘贴。为了避免页眉和页脚部分的 HTML 代码四处复制,我们使用“include”指令在每个页面中包含一段 HTML 代码。

使用 #Include 指令的问题

然而,正如大多数 Web 开发人员(包括我)已经经历过的那样,这种“include”方法存在一些缺点。

  1. 我们需要记住在每个 ASP 页面中插入 include 指令的确切位置。
  2. 没有逻辑可以对页眉包含文件和页脚包含文件进行分组,如果我们希望为站点的不同部分(例如管理部分、已登录部分和公共部分)拥有多套页眉和页脚,我们最终会得到六个不同的页眉和页脚文件,它们之间完全不相关。
  3. 我们无法在运行时动态包含不同的文件。

使用控件的替代方法

这个简单的演示说明了一种为 Web 应用程序的所有网页添加页眉和页脚用户控件的替代方法。基本思想是使用 HTTP 模块以编程方式将控件插入到页面中的正确位置。

以下是实现 HTTP 模块的步骤概述

  1. 创建一个参与页面执行周期的 HTTP 模块。
  2. 为页面 init 事件注册一个事件处理程序。
  3. 在页面 init 事件处理程序中,查找“Form”控件。
  4. 实例化页眉和页脚控件,并将其添加到“Form”控件中。
  5. Web.Config 中注册 HTTP 模块。

实现细节

创建 HTTP 模块

要创建 HTTP 模块,我们只需编写一个实现 System.Web.IHttpModule 接口的类。该接口要求实现两个方法:InitDispose。通常,在实现 HTTP 模块时,我们会在 Init 方法中注册事件处理程序,以便在 HTTP 请求的处理到达某个阶段时执行它们。在我们的示例中,我们将在处理 HTTP 请求的处理程序实例准备好的阶段注册事件处理程序,即 PreRequestHandlerExecute 事件。

// Note: Make sure you have the following namespace included in your

// code:

using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.HtmlControls;
-----------------------------------------
public class HeaderFooterModule : IHttpModule{

    public HeaderFooterModule()
    {
    }

    public void Init(HttpApplication context)
    {
        //Register the event handler for PreRequestHandlerExecute event in 

        //the HTTP Request handling cycle

        context.PreRequestHandlerExecute += 
                   new EventHandler(context_PreRequestHandlerExecute);
    }

    private void context_PreRequestHandlerExecute(object sender, EventArgs e)
    {
        //See next code block for implementation of this handler        

    }

    public void Dispose()
    {
    }
}

为页面 Init 事件注册事件处理程序

当请求处理到达“Pre request handler execute”阶段时,处理程序实例已准备就绪。处理程序可以是任何实现 IHttpHandler 的内容,它可以是网页或一些其他请求处理程序。因此,我们需要过滤掉定向到页面的 HTTP 请求。为此,我们检查请求处理程序的类型,并确保它是一个 HTTP 页面。(稍后,我们可以添加一些其他附加逻辑,用于根据页面类型添加控件)。一旦我们确定处理程序是 Page 对象,我们就需要在其 init 事件中注册另一个事件处理程序,以将控件插入到正确的位置。在页面执行周期中,init 事件是页面控件已初始化的位置。这就是我们定位“Form”控件并添加其他代码以放置我们自己的页眉和页脚控件的地方,以便它可以在其余的页面执行阶段中使用。要定位 form 控件,我们只需迭代 PageControls 集合。form 控件应该位于 PageControls 集合的前几个元素中,因此遍历它们应该不是大问题。

    private void context_PreRequestHandlerExecute(object sender, EventArgs e)
    {
        //Get the Request handler from the Context

        HttpContext oContext = ((HttpApplication)sender).Context;
        //Check if the request handler is a Page object

        if (oContext.Handler is Page)
        { 
            Page objPage = (Page)oContext.Handler;
            //Register an event handler for the page init event            

            objPage.Init += new EventHandler(Page_Init);
        }        
    }

    private void Page_Init(object sender, EventArgs e)
    {
        //See next code block for implementation of this handler        

    }

实现页面 Init 事件处理程序的事件处理程序

在页面 Init 事件处理程序中,我们需要查找“Form”元素,实例化页眉和页脚控件(使用用户控件 .ascx 文件),并将控件放置在页面中。用于页眉和页脚的控件是使用 Visual Studio .NET 创建的用户控件。这包括一个 ascx 文件和一个代码隐藏文件。您可以在用户控件中放入其他服务器控件,例如登录按钮,并将处理登录按钮单击的代码放在用户控件的代码隐藏中。

    private void Page_Init(object sender, EventArgs e)
    {
        //Iterate through the control collection for the page

        foreach (Control objControl in ((Page)sender).Controls) 
        {
            if (objControl is HtmlForm) 
            {
                HtmlForm objForm = (HtmlForm)objControl;
                //Instantiate and add the control to the page 

                //using the .ASCX file

                objForm.Controls.AddAt(0, 
                    objForm.Page.LoadControl("Header.ascx"));
                objForm.Controls.Add(objForm.Page.LoadControl("Footer.ascx"));
                break;
            }
        }
    }

在 web.config 文件中注册模块

要注册 HTTP 模块,只需在 web.config 文件的 system.web 元素中添加以下配置段:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.web>
    <httpModules>
      <add name="HeaderFooterModule" 
           type="MyNamespace.HeaderFooterModule,MyAssembly"/>
    </httpModules>
  </system.web>
</configuration>

变奏

对于具有不同部分(例如管理部分和公共页面部分)的站点,我们可能希望使用不同的页眉和页脚设计。在这种情况下,一种可能的方案是让这些部分中的页面实现不同的标记接口。标记接口基本上是一个没有定义任何方法的接口。如果您只是想识别页面是否属于某个特定类别,它特别有用。例如,我们可以将上面的 Page_Init 处理程序实现替换为以下代码,以便它检查页面类型并确定要使用的适当的页眉和页脚 ascx 文件:

private void Page_Init(object sender, EventArgs e)
{
  //Iterate through the control collection for the page

  foreach (Control objControl in ((Page)sender).Controls) 
  {
    if (objControl is HtmlForm) 
    {
      HtmlForm objForm = (HtmlForm)objControl;
      if (sender is IAdminPage) 
      {
        //Instantiate and add the admin control to the page using 

        //the .ASCX file

        objForm.Controls.AddAt(0, 
          objForm.Page.LoadControl("AdminHeader.ascx"));
        objForm.Controls.Add(objForm.Page.LoadControl("AdminFooter.ascx"));
      }
      else
      {
        //Instantiate and add the regular control to the page 

        //using the .ASCX file

        objForm.Controls.AddAt(0,objForm.Page.LoadControl("Header.ascx"));
        objForm.Controls.Add(objForm.Page.LoadControl("Footer.ascx"));
      }    
      break;
    }
  }
}

对于管理页面的代码隐藏类

public interface IAdminPage {
}
public class HeaderFooterModule : Page, IAdminPage{
    ...
}

关于以编程方式向页面添加控件的特别说明

需要注意的是,使用这种方法,您不能直接在 ASP.NET 页面中编写代码片段。虽然这可能引起一些人的担忧,但我认为这并不是一个大问题,因为我相信大多数代码片段都可以被控件替代。

结论

通过这种使用 HTTP 模块添加页眉和页脚控件的方法,我们可以实现以下目标:

  1. 在不修改 ASP.NET 页面的任何内容的情况下,为所有页面添加统一的页眉和页脚。
  2. 可以为不同的部分拥有不同套的页眉和页脚。所有页面只需要实现适当的标记接口。
  3. 能够修改模块以添加额外的逻辑(例如基于用户凭据...)来实例化和插入不同的页眉/页脚控件。
© . All rights reserved.