目的
实现用MasterPage中的cs文件 代替项目中的PageBase动机
写这篇文章的动机来自于一次项目重构在Net Framwork 的B/S架构项目中同时采用PageBase和MasterPage技术发现每次访问页面页面同时访问PageBase和MasterPage不仅造成性能降低甚至有可能给日后的项目功能扩充和调整带来逻辑错误隐患技术环节
PageBaseNet Framework 中经常使用的一种封装多个页面相同功能的技术PageBasecs类继续自SystemWebUIPage类项目中的Web页面继续自PageBasecs类通过重写基类中的页面初始化方法实现调用PageBase中的业务功能例如url参数验证保存访问量等功能(具体实现方式参见微软官方例子duwamishi)
MasterPageNet Framework 中新特性物理上包括两个文件分别是Master文件(Html标记)cs文件(C#代码)Master文件实现显示层绘制cs文件实现具体功能继续自MasterPage的Web页面可以继续MasterPage中的显示层内容绘制通用的页头页脚定制统一的布局MasterPage是不错的选择模拟需求
用MasterPage技术代替PageBase实现地址栏参数验证
简单的做个解释吧
登录系统之后url地址栏中带有参数如下
此时用户手动修改url地址栏中参数为
被视为非法操作系统将自动跳转回登录页面
第一次代码迭代
参照传统PageBase方法
传统的Page做法为
public class PageBase : SystemWebUIPage
{
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)
{
baseInitialize();
}
}
参照其做法将PageBase中的代码移入MasterPage中
MasterPagecs
public partial class MyMasterPage : SystemWebUIMasterPage
{
protected void Page_Load(object sender EventArgs e)
{
if (!IsPostBack)
{
// 调用验证方法
Initialize();
}
}
}
将Web页面中的代码修改为
public partial class TestPage : SystemWebUIPage
{
// 仿照PageBase方法调用Master中的方法
/**//// <summary>
/// 重写基类OnPreInit() 方法调用通用验证方法
/// </summary>
/// <param name=e></param>
protected override void OnInit(eventargs e)
{
// 获得母板页引用
MyMasterPage myMasterPage = (MyMasterPage)thisMaster;
// 调用母板页中通用验证方法
if (!IsPostBack)
{
myMasterPageInitialize();
}
}
}将MasterPage中的Initialize()方法替换为实例中的测试代码
步骤用 用户名zhangsan登录系统登录成功
页面显示 欢迎 zhangsan 登录
url地址显示
步骤手动修改url地址栏如下
页面不会显示 欢迎lisi登录而是跳转回登录页面
反思虽然功能实现但是存在不理想的环节
Master中的被子类调用方法必须是public方法
虽然不用修改Web页的继续但是依然要机械的复制粘贴重写基类的OnInit()方法
为了消除这些怀味道于是开始
第二次代码迭代
修改MasterPagecs中的代码
public partial class MyMasterPage : SystemWebUIMasterPage
{
protected void Page_Load(object sender EventArgs e)
{
if (!IsPostBack)
{
// 调用验证方法
CheckLogin();
}
}
/**//// <summary>
/// 验证访问是否合法
/// </summary>
private void CheckLogin()
{
// 假如 url中的编号 或 cookie中的编号
if (stringIsNullOrEmpty(RequestQueryString[id])
stringIsNullOrEmpty(CookieUtilReadCookieByKey(id)))
{
ResponseRedirect(LoginASPx);
}// 假如url中的编号 和 cookie中的编号 不匹配返回登录页
else if (intParse(RequestQueryString[id]) != intParse(CookieUtilReadCookieByKey(id)))
{
ResponseRedirect(Loginaspx);
}
}
}重构之后Web页可以不进行任何修改MasterPage在自身的Page_Load()方法中自动调用验证方法而且将验证方法设置为private仅供MasterPage自身调用提高安全性至此代码似乎比较理想了测试
步骤一用 用户名 zhangsan登录系统
依然显示用户登录页面
测试失败
用断点跟蹤代码发现问题出现在MasterPagecs中的CheckLogin()方法中的代码片段
if (stringIsNullOrEmpty(RequestQueryString[id])
stringIsNullOrEmpty(CookieUtilReadCookieByKey(id)))
{
ResponseRedirect(Loginaspx);
}
由于登录页继续自MasterPage所以页面加载时自动调用MasterPagecs中的验证方法而自身的参数又不满足stringIsNullOrEmpty()方法于是又跳回到登录页面登录页面在再次在加载时调用基类中的验证方法于是形成死循环
在PageBase技术中Web页面可以有选择的继续自PageBase而MasterPage技术中为了获得一致的显示层效果Web页面对继续MasterPage的选择性是非常底的而且我们也不应该采用新建相同显示不带有验证代码的MasterPage来给不需要继续基类功能的Web页面来继续这种方式显然不合理为了解决这个问题于是开始了
第三次迭代
引入配置文件
<?XML version= encoding=utf ?>
<pages>
<testpage>
<page title=TestPage url=TestPageaspx needvalidate=true/>
<page title=Login url=Loginaspx needvalidate=false/>
</testpage>
<adminpages>
<page title=Page url=~/Admin/Pageaspx needvalidate=false/>
<page title=Page url=~/Admin/Pageaspx needvalidate=false/>
</adminpages>
</pages>
从中可以看到将需要验证的页面加以标识(needvalidate=true)
创建Xml数据访问类
public class XmlDAL
{
private static string filePath = stringEmpty;
static XmlDAL()
{
// 初始化配置文件路径
filePath = HttpContextCurrentRequestMapPath(~/App_Data/xml/ + Pagesxml);
}
/**//// <summary>
/// 获得需要验证的页面列表
/// </summary>
/// <returns>需要验证的页面列表</returns>
public static IList<string> GetValidatePages()
{
IList<string> pages = new List<string>();
// 假如指定配置文件存在
if (SystemIOFileExists(filePath))
{
try
{
XmlDocument xmlDoc = new XmlDocument();
xmlDocLoad(filePath);
// 获取配置文件根节点
XmlNode root = xmlDocDocumentElement;
string XPath = /pages/testpage/page[@needvalidate=true];
XmlNodeList nodeList = rootSelectNodes(xpath);
// 便利节点集合
foreach (XmlNode node in nodeList)
{
pagesAdd(nodeAttributes[title]Value);
}
}
catch (Exception ex)
{
throw new Exception(exMessage);
}
}
return pages;
}
}
重构MasterPagecs中的代码加入IsValidateNeeded(string url)方法用于检测当前页面是否需要验证修改验证方法
public partial class MyMasterPage : SystemWebUIMasterPage
{
protected void Page_Load(object sender EventArgs e)
{
if (!IsPostBack)
{
// 调用验证方法
CheckLogin();
}
}
/**//// <summary>
/// 验证访问是否合法
/// </summary>
private void CheckLogin()
{
// 判定当前访问页面是否需要进行验证
if (IsValidateNeeded(RequestRawUrl))
{
// 假如 url中的编号 或 cookie中的编号
if (stringIsNullOrEmpty(RequestQueryString[id])
stringIsNullOrEmpty(CookieUtilReadCookieByKey(id)))
{
ResponseRedirect(Loginaspx);
}// 假如url中的编号 和 cookie中的编号 不匹配返回登录页
else if (intParse(RequestQueryString[id]) != intParse(CookieUtilReadCookieByKey(id)))
{
ResponseRedirect(Loginaspx);
}
}
}
/**//// <summary>
/// 验证当前页是否需要验证
/// </summary>
/// <param name=currentPage>当前页面名称</param>
/// <returns>是否需要验证状态</returns>
private bool IsValidateNeeded(string url)
{
bool isNeeded = false;
// GetValidatePages() 方法返回需要验证页面列表
IList<string> pages = XmlDALGetValidatePages();
IEnumerator<string> ie = pagesGetEnumerator();
while (ieMoveNext())
{
// 假如当前页面需要进行验证
if (urlContains(ieCurrent))
// 返回需要验证状态
return isNeeded = true;
}
return isNeeded;
}
}
进行测试
步骤用 用户名zhangsan登录系统登录成功
页面显示 欢迎 zhangsan 登录
url地址显示
步骤手动修改url地址栏如下
页面不会显示 欢迎lisi登录而是跳转回登录页面至此我的代码迭代结束了