基于PageHandlerFactory的路径重写

现在在.net中,我们有很多方法可以实现路径的重写,不论是外部插件还是代码控制,总归是为了让URL对外更加的短小,易懂并且不包含敏感信息.

所以,在这里,我主要介绍如何利用PageHandlerFactory类来拦截URL请求并且进行重写的.

这里类是所有的aspx页面请求的默认父类对象,页面的任何请求都可以被其捕获,我们可以通过重写其中的getHandler方法来实现自我控制.

功能需求

不过,在开始写之前,我们先看看我们需要用到什么功能.

  1. URL重写需要支持GET, POST请求方式.
  2. URL重写需要支持实时的DEBUG功能,也就是能够跳转到重新定向的页面进行调试.

代码构建

基于这两点(其实这两点在开发过程中也是很重要的两点),我们构建如下的代码页:

using System.Web;
using System.Web.UI;
using System.Web.SessionState;
using System;

namespace AsyncFactoryWEB
{
    public class RewriterFactory : PageHandlerFactory,IReadOnlySessionState
    {
        private bool flag = true;

        public override IHttpHandler GetHandler(HttpContext context, string requestType, string virtualPath, string path)
        {
            string[] urlSegments = context.Request.Url.Segments; //获取URL片段
            int urlLen = urlSegments.Length;  //获取URL的片段长度
            if (urlLen <= 1) //当前请求为根目录页面,则不进行处理
                flag = false;
            else  //当前请求不是根目录页面,进行处理
                flag = true;

            if (flag)
            {
                string conceratePath = ((char)RewriteSettings.splitter.slash).ToString(); 

                string slashChar = ((char)RewriteSettings.splitter.slash).ToString(); // /斜线
                string equalChar = ((char)RewriteSettings.splitter.equal).ToString(); // =等号
                string andChar   = ((char)RewriteSettings.splitter.and  ).ToString(); // &符号
                string extension = ((char)RewriteSettings.splitter.dot  ).ToString().Combine(RewriteSettings.fileExtension.aspx.ToString());  // .aspx后缀

                string concerateParams=string.Empty;
                for (int i = 0; i < urlLen; i++) 
                {
                    string curSegment = urlSegments[i];

                    if (curSegment.LastIndexOf(slashChar) >= 0)  //如果检测片段中带有左斜线
                        curSegment = curSegment.Substring(0, curSegment.Length - 1); //将斜线去掉

                    if (!string.IsNullOrEmpty(curSegment)) 
                    {
                        if (curSegment.Contains(equalChar)) //如果带有等号,则表明应该进行 ***.aspx?id=1 类似的拼接
                        {
                            if (i == urlLen - 1)
                                concerateParams = concerateParams.Combine(curSegment);
                            else
                                concerateParams = concerateParams.Combine(curSegment.Combine(andChar));
                        }
                        else if (!curSegment.EndsWith(extension)) //如果不是以.aspx结尾的
                            conceratePath = conceratePath.Combine(curSegment.Combine(extension));
                        else
                            conceratePath = conceratePath.Combine(curSegment);
                    }
                }

                string newPath = context.Server.MapPath(conceratePath); //得到物理目录
                 
                context.RewritePath(conceratePath, string.Empty, concerateParams); //重写路径,并传入parameters

                try
                {
                    IHttpHandler iHandler = PageParser.GetCompiledPageInstance(conceratePath, newPath, context);  //重写handler对象
                    return iHandler; 
                }
                catch (Exception ex)
                {
                    throw new Exception(ex.Message);
                }
               
            }
            else
            {
                return base.GetHandler(context, requestType, virtualPath, path);
            }
        }
    }
}
View Code

代码注释比较清楚,就是先获取URL路径,然后进行处理拼接,最后返回一个Handler对象即可.

下面来测试以下, 在Default.aspx中,我们前台代码如下:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="AsyncFactoryWEB._Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Url Rewrite testing daemon</title>
</head>
<body>
    <div>Using Get method to <a href="WebForm1/type=0/partype=1/testUserName=myRobot/">redirect</a> another page.</div><br />
    <hr style="height:1px;" />
    <form id="form1"  action="WebForm1/t=1/" method="post">
    <div>Using Post method to redirect another page.</div>
    <div>
        UserName:<input type="text" name="UserName" style="border:none;border-bottom:1px solid black;"/><br />
        UserPhone:<input type="text" name="UserPhone" style="border:none;border-bottom:1px solid black;"/><br />
        <input type="submit" value="Send" /><br />
    </div>
    </form>
    <hr style="height:1px;" />
</body>
</html>
View Code

可以看出其中有两种测试方式:

Get方式:

<a href="WebForm1/type=0/partype=1/testUserName=myRobot/">redirect</a>

Post方式: 

<form id="form1"  action="WebForm1/t=1/" method="post">

跳转页面为WebForm1.aspx,后台代码为:

using System;
using System.Web.UI;
using System.Collections.Specialized;

namespace AsyncFactoryWEB
{
    public partial class WebForm1 :Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            Response.Write("-----------------Using GET Method---------------------<br/>");
            NameValueCollection queryStringCollection = Request.QueryString;
            foreach (string key in queryStringCollection.Keys)
            {
                Response.Write(string.Format("QueryString [{0}] value : {1} ",key,queryStringCollection[key]));
                Response.Write("<br/>");
            }
            Response.Write("-----------------Using POST Method---------------------<br/>");
            NameValueCollection formStringCollection = Request.Form;
            foreach (string key in formStringCollection.Keys)
            {
                Response.Write(string.Format("FormString [{0}] value : {1} ", key, formStringCollection[key]));
                Response.Write("<br/>");
            }
        }
    }
}
View Code

测试结果

当利用Get方式测试时候,我们会跳转到WebForm1.aspx, 显示结果如图:

-----------------Using GET Method---------------------
QueryString [type] value         : 0 
QueryString [partype] value      : 1 
QueryString [testUserName] value : myRobot 
-----------------Using POST Method---------------------

可以看到成功获取了数据.

当利用Post方式测试的时候,我们会跳转到WebForm1.aspx,显示结果如图:

-----------------Using GET Method---------------------
QueryString [t] value        : 1 
-----------------Using POST Method---------------------
FormString [UserName] value  : 程序诗人 
FormString [UserPhone] value : 13103993996 

数据均能正确捕获.

那么调试功能怎么样呢? 当我们在webForm1.aspx中打上断点的时候,由于PageHandlerFactory会捕获所有请求,所以当返回创建的Hander的时候,会调用processrequest来处理WebForm1.aspx中的方法调用,所以会进入断点.

当然,在上述示例中,我定义的URL实在是太过于难看,你可以自定义自己的URL解析规则.

最后,我们需要在web.config文件<httpHandlers>中加上节点配置.

 <add  verb="*" path="*" type="AsyncFactoryWEB.RewriterFactory,AsyncFactoryWEB"/>

希望对你有用.

 代码下载

点击这里下载

展开阅读全文

没有更多推荐了,返回首页