设为首页
加入收藏
站内地图
旧版入口
当前位置:首页 > 站长学院 > 网络编程 > ASP.NET

用MasterPage 代替 PageBase

作者:佚名 出处:网络转载 时间:11-08 点击:

内容载入中...
     目的:
   实现用MasterPage中的.cs文件 代替项目中的PageBase。
  
  动机:
   写这篇文章的动机,来自于一次项目重构。在.Net Framwork 2.0的B/S架构项目中同时采用PageBase和MasterPage技术,发现每次访问页面,页面同时访问PageBase和MasterPage,不仅造成性能降低,甚至有可能给日后的项目功能扩充和调整带来逻辑错误隐患。
  
  技术环节:
   PageBase:.Net Framework 1.1 中经常使用的一种封装多个页面相同功能的技术。PageBase.cs类继承自System.Web.UI.Page类,项目中的Web页面继承自PageBase.cs类,通过重写基类中的页面初始化方法,实现调用PageBase中的业务功能,例如:url参数验证,保存访问量等功能(具体实现方式参见微软官方例子duwamishi)。
   MasterPage:.Net Framework 2.0 中新特性,物理上包括两个文件,分别是:.Master文件(HTML标记),.cs文件(C#代码)。.Master文件实现显示层绘制,.cs文件实现具体功能。继承自MasterPage的Web页面可以继承MasterPage中的显示层内容。绘制通用的页头页脚,定制统一的布局,MasterPage是不错的选择。
  
  模拟需求:
   用MasterPage技术,代替PageBase,实现地址栏参数验证。
  简单的做个解释吧,数据库中Login表信息如下图:
  
  登录系统之后,url地址栏中带有参数,如下:
  http://localhost:3730/MasterPageBaseDemo/TestPage.ASPx?id=1001
  此时用户手动修改url地址栏中参数为:
  http://localhost:3730/MasterPageBaseDemo/TestPage.ASPx?id=1002
  被视为非法操作,系统将自动跳转回登录页面。
  
  
  第一次代码迭代:
  
  
  1.参照传统PageBase方法:
   传统的Page做法为:
  public class PageBase : System.Web.UI.Page
  {
   public PageBase()
   {
   }
   /**//// <summary>
   /// 入口方法
   /// </summary>
   protected void Initialize()
   {
   // 插入通用业务逻辑
   }
  }
   Web页面:
  public partial class TestPage : PageBase
  {
   // 传统的调用PageBase的方法
   /**///// <summary>
   /// 重写基类OnPreInit() 方法,调用通用验证方法
   /// </summary>
   /// <param name="e"></param>
   protected override void OnInit(eventargs e)
   {
   base.Initialize();
   }
  }
  参照其做法,将PageBase中的代码移入MasterPage中:
  MasterPage.cs:
  public partial class MyMasterPage : System.Web.UI.MasterPage
  {
   protected void Page_Load(object sender, EventArgs e)
   {
   if (!IsPostBack)
   {
   // 调用验证方法
   Initialize();
   }
   }
  }
  将Web页面中的代码修改为:
  public partial class TestPage : System.Web.UI.Page
  {
   // 仿照PageBase方法,调用Master中的方法
   /**//// <summary>
   /// 重写基类OnPreInit() 方法,调用通用验证方法
   /// </summary>
   /// <param name="e"></param>
   protected override void OnInit(eventargs e)
   {
   // 获得母板页引用
   MyMasterPage myMasterPage = (MyMasterPage)this.Master;
   // 调用母板页中通用验证方法
   if (!IsPostBack)
   {
   myMasterPage.Initialize();
   }
   }
  }将MasterPage中的Initialize()方法替换为实例中的,测试代码:
   步骤1:用 用户名zhangsan登录系统,登录成功,
   页面显示 欢迎 zhangsan 登录。
   url地址显示:
   http://localhost:3730/MasterPageBaseDemo/TestPage.ASPx?id=1001
   步骤2:手动修改url地址栏:如下:
   http://localhost:3730/MasterPageBaseDemo/TestPage.ASPx?id=1002
   页面不会显示 欢迎lisi登录,而是跳转回登录页面。
  反思:虽然功能实现,但是存在不理想的环节:
   1. Master中的被子类调用方法必须是public方法;
   2. 虽然不用修改Web页的继承,但是依然要机械的复制粘贴重写基类的OnInit()方法。
  为了消除这些怀味道,于是开始:
  第二次代码迭代:
  修改MasterPage.cs中的代码:
  public partial class MyMasterPage : System.Web.UI.MasterPage
  {
   protected void Page_Load(object sender, EventArgs e)
   {
   if (!IsPostBack)
   {
   // 调用验证方法
   CheckLogin();
   }
   }
   /**//// <summary>
   /// 验证访问是否合法
   /// </summary>
   private void CheckLogin()
   {
   // 如果 url中的编号 或 cookie中的编号
   if (string.IsNullOrEmpty(Request.QueryString["id"])
   || string.IsNullOrEmpty(CookieUtil.ReadCookieByKey("id")))
   {
   Response.Redirect("Login.ASPx");
   }// 如果url中的编号 和 cookie中的编号 不匹配,返回登录页
   else if (int.Parse(Request.QueryString["id"]) != int.Parse(CookieUtil.ReadCookieByKey("id")))
   {
   Response.Redirect("Login.ASPx");
   }
   }
  }重构之后,Web页可以不进行任何修改,MasterPage在自身的Page_Load()方法中自动调用验证方法,而且将验证方法设置为private,仅供MasterPage自身调用,提高安全性。至此,代码似乎比较理想了,测试:
   步骤一:用 用户名 zhangsan登录系统,
   依然显示用户登录页面。
   测试失败。
  用断点跟踪代码,发现问题出现在MasterPage.cs中的CheckLogin()方法中的代码片段:
  if (string.IsNullOrEmpty(Request.QueryString["id"])
   || string.IsNullOrEmpty(CookieUtil.ReadCookieByKey("id")))
  {
   Response.Redirect("Login.ASPx");
  }
  由于登录页继承自MasterPage,所以页面加载时自动调用MasterPage.cs中的验证方法,而自身的参数又不满足string.IsNullOrEmpty()方法,于是又跳回到登录页面,登录页面在再次在加载时调用基类中的验证方法,于是形成死循环。
  在PageBase技术中,Web页面可以有选择的继承自PageBase,而MasterPage技术中,为了获得一致的显示层效果,Web页面对继承MasterPage的选择性是非常底的,而且我们也不应该采用新建相同显示,不带有验证代码的MasterPage,来给不需要继承基类功能的Web页面来继承,这种方式显然不合理。为了解决这个问题,于是开始了
  第三次迭代:
  引入配置文件:
  <?xml version="1.0" encoding="utf-8" ?>
  <pages>
   <testpage>
   <page title="TestPage" url="TestPage.aspx" needvalidate="true"/>
   <page title="Login" url="Login.aspx" needvalidate="false"/>
   </testpage>
   <adminpages>
   <page title="Page1" url="~/Admin/Page1.aspx" needvalidate="false"/>
   <page title="Page2" url="~/Admin/Page2.aspx" needvalidate="false"/>
   </adminpages>
  </pages>
  从中可以看到,将需要验证的页面加以标识(needvalidate="true")。
  创建XML数据访问类:
  public class XMLDAL
  {
   private static string filePath = string.Empty;
   static XMLDAL()
   {
   // 初始化配置文件路径
   filePath = HttpContext.Current.Request.MapPath("~/App_Data/XML/" + "Pages.XML");
   }
   /**//// <summary>
   /// 获得需要验证的页面列表
   /// </summary>
   /// <returns>需要验证的页面列表</returns>
   public static IList<string> GetValidatePages()
   {
   IList<string> pages = new List<string>();
   // 如果指定配置文件存在
   if (System.IO.File.Exists(filePath))
   {
   try
   {
   XMLDocument XMLDoc = new XMLDocument();
   XMLDoc.Load(filePath);
   // 获取配置文件根节点
   XMLNode root = XMLDoc.DocumentElement;
   string xpath = "/pages/testpage/page[@needvalidate="true"]";
   XMLNodeList nodeList = root.SelectNodes(xpath);
   // 便利节点集合
   foreach (XMLNode node in nodeList)
   {
   pages.Add(node.Attributes["title"].Value);
   }
   }
   catch (Exception ex)
   {
   throw new Exception(ex.Message);
   }
   }
   return pages;
   }
  }
  重构MasterPage.cs中的代码,加入IsValidateNeeded(string url)方法,用于检测当前页面是否需要验证,修改验证方法:
  public partial class MyMasterPage : System.Web.UI.MasterPage
  {
   protected void Page_Load(object sender, EventArgs e)
   {
   if (!IsPostBack)
   {
   // 调用验证方法
   CheckLogin();
   }
   }
   /**//// <summary>
   /// 验证访问是否合法
   /// </summary>
   private void CheckLogin()
   {
   // 判断当前访问页面是否需要进行验证
   if (IsValidateNeeded(Request.RawUrl))
   {
   // 如果 url中的编号 或 cookie中的编号
   if (string.IsNullOrEmpty(Request.QueryString["id"])
   || string.IsNullOrEmpty(CookieUtil.ReadCookieByKey("id")))
   {
   Response.Redirect("Login.ASPx");
   }// 如果url中的编号 和 cookie中的编号 不匹配,返回登录页
   else if (int.Parse(Request.QueryString["id"]) != int.Parse(CookieUtil.ReadCookieByKey("id")))
   {
   Response.Redirect("Login.ASPx");
   }
   }
   }
   /**//// <summary>
   /// 验证当前页是否需要验证
   /// </summary>
   /// <param name="currentPage">当前页面名称</param>
   /// <returns>是否需要验证状态</returns>
   private bool IsValidateNeeded(string url)
   {
   bool isNeeded = false;
   // GetValidatePages() 方法返回需要验证页面列表
   IList<string> pages = XMLDAL.GetValidatePages();
   IEnumerator<string> ie = pages.GetEnumerator();
   while (ie.MoveNext())
   {
   // 如果当前页面需要进行验证
   if (url.Contains(ie.Current))
   // 返回需要验证状态
   return isNeeded = true;
   }
   return isNeeded;
   }
  }
  进行测试:
   步骤1:用 用户名zhangsan登录系统,登录成功,
   页面显示 欢迎 zhangsan 登录。
   url地址显示:
   http://localhost:3730/MasterPageBaseDemo/TestPage.ASPx?id=1001
   步骤2:手动修改url地址栏:如下:
   http://localhost:3730/MasterPageBaseDemo/TestPage.ASPx?id=1002
   页面不会显示 欢迎lisi登录,而是跳转回登录页面。
  
  至此我的代码迭代结束了。
  代码下载:
  http://www.cnblogs.com/Files/ayuan/MasterPageBaseDemo.rar
  本人之前没有写技术文章的经验,所以以上的文字难免晦涩,而且自身技术水平也有限,可能有些观点不太成熟,欢迎各位朋友指正.
    。

收藏本文:
】【打印页面】【推荐给朋友】【关闭窗口

站长学院

推荐信息