URL重写及干掉ASP.NET试图状态的实现方法_实用技巧

1、URL重写已经很普遍了,但基本上大部分的URL重写都不支持页面的相对路径,所有如果想在已经开发好的项目中添加还是有压力的,第二就是例如微软的那个URL重写是根据正则表达式来处理的,那样是很好,但也有不足之处,就是不方便定位到某个页面只能有哪些参数。
我觉得要解决的问题有一下几个:
1、解决如图片js等不能使用相对路径的文件
2、解决某个页面能有几个参数和哪些参数是可选的
下面就是解决掉这些问题了
  添加处理程序MyHttpModule,下面是我的一个简单的处理程序(我只是做了一个简单的,并没有考虑性能,而且我是写死的一个url重写就是重写成没有扩展名的)

复制代码 代码如下:

using System;
using System.Collections.Generic;
using System.Web;
using System.IO;
using System.Text;
namespace MyClass
{
public class MyHttpModule : IHttpModule
{
#region IHttpModule 成员
///<summary>
/// 释放所有资源
///</summary>
public void Dispose()
{
}
///<summary>
/// 初始化模块,并使其为处理请求做好准备
///</summary>
///<param name="context"> 一个 System.Web.HttpApplication,它提供对 ASP.NET 应用程序内所有应用程序对象的公用的方法、属性和事件的访问</param>
public void Init(HttpApplication context)
{
context.AuthorizeRequest += new
EventHandler(this.BaseModuleRewriter_AuthorizeRequest);
}
///<summary>
/// 当安全模块已验证用户授权时发生
///</summary>
///<param name="sender"></param>
///<param name="e"></param>
protected virtual void BaseModuleRewriter_AuthorizeRequest(
object sender, EventArgs e)
{
System.Web.HttpApplication app = (System.Web.HttpApplication)sender;
Rewrite(app.Request.Path, app);
}
///<summary>
/// 重写url
///</summary>
///<param name="requestedPath">url的虚拟路径</param>
///<param name="app"></param>
protected void Rewrite(string requestedPath, System.Web.HttpApplication app)
{
List<string> qeryString;
string virtualPath;
string inputFile = GetInputFile(app.Context, out virtualPath, out qeryString);//获取到真实的文件信息
if (System.IO.Path.GetExtension(inputFile) == ".aspx")//如果是aspx文件 那么则把保留重写的url
{
app.Context.RewritePath(requestedPath, string.Empty, string.Empty);//这里查询参数我没去处理了,也就是Request.QueryString的信息,如果取qeryString 然后去处理成一个字符串
return;
}
app.Context.RewritePath(virtualPath, string.Empty, app.Context.Request.QueryString.ToString());//其它文件则使用找到的路径
}
///<summary>
/// 获取url对应的绝对路径和虚拟路径及查询参数
///</summary>
///<param name="context"></param>
///<param name="virtualPath">虚拟路径</param>
///<param name="qeryString">查询参数 如果为null请取HttpContext.Request.QueryString</param>
///<returns>url对应的绝对路径</returns>
public static string GetInputFile(HttpContext context, out string virtualPath, out List<string> qeryString)
{
string executionFilePath = context.Request.AppRelativeCurrentExecutionFilePath.Remove(0, 2);//获取当前对应的虚拟路径并干掉“~/”
string inputFile = context.Request.PhysicalPath;//获取当前url对于的绝对路径
virtualPath = context.Request.AppRelativeCurrentExecutionFilePath;
qeryString = null;
List<string> qeryList = new List<string>();
if (!File.Exists(inputFile))//判断文件是否存在,也就是没有被重写的url获取使用绝对路径的资源等等
{
bool b = false;
string fileName;
string extension;
string applicationPath = context.Request.PhysicalApplicationPath;//获取网站的跟目录
var tempPath = GetFileInfo(inputFile, out fileName, out extension);
while (!b)//根据目录循环获取有效的文件目录
{
b = File.Exists(tempPath + "\\" + extension);//判断文件是否存在
if (tempPath + "\\" == applicationPath)//如果查找到根目录还没有查找到那么则不需要在查了
{
break;
}
if (!string.IsNullOrWhiteSpace(fileName))
{
qeryList.Add(fileName);//如果不存在那么这个就是参数 例如http://localhost:4688/WebForm1/2011/ (对应http://localhost:4688/WebForm1.aspx?xxx=2011)
}
tempPath = GetFileInfo(tempPath, out fileName, out extension);
}
if (b)//如果查找到了就把查找到的路径复制给输出或返回参数
{
inputFile = tempPath + "\\" + extension;
virtualPath = "~/" + inputFile.Replace(applicationPath, null);
}
if (Path.GetExtension(extension) == ".aspx")//如果是asp.net那么则把list复制给输出参数 qeryString
{
qeryString = qeryList;
}
}
return inputFile;
}
///<summary>
/// 获取指定目录+文件是否有效
///</summary>
///<param name="inputFile">目录</param>
///<param name="fileName"></param>
///<param name="extension"></param>
///<returns></returns>
private static string GetFileInfo(string inputFile, out string fileName, out string extension)
{
var tempPath = Directory.GetParent(inputFile).FullName;//获取传进来目录的父目录
fileName = inputFile.Replace(tempPath + "\\", null);//获取子目录名称
extension = Path.GetExtension(inputFile);//获取扩展名
if (string.IsNullOrWhiteSpace(extension))//如果扩展名为null那么则认为是aspx文件
{
extension = fileName + ".aspx";
}
else
{
extension = fileName + extension;
}
return tempPath;
}
#endregion
}
}

因为我在处理aspx页面时还是传入的重写后的路径,所有我们还有添加一个继承IHttpHandlerFactory的类
代码如下:

复制代码 代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.IO;
using System.Web.UI;
namespace MyClass
{
public class MyHttpHandlerFactory:IHttpHandlerFactory
{
#region IHttpHandlerFactory 成员
///<summary>
/// 返回实现 System.Web.IHttpHandler 接口的类的实例
///</summary>
///<param name="context">System.Web.HttpContext 类的实例,它提供对用于为 HTTP 请求提供服务的内部服务器对象(如 Request、Response、Session和 Server)的引用</param>
///<param name="requestType">客户端使用的 HTTP 数据传输方法(GET 或 POST)</param>
///<param name="url">所请求资源的 System.Web.HttpRequest.RawUrl</param>
///<param name="pathTranslated">所请求资源的 System.Web.HttpRequest.PhysicalApplicationPath</param>
///<returns>处理请求的新的 System.Web.IHttpHandler 对象</returns>
public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
{
List<string> qeryString;
string virtualPath;
string inputFile =MyHttpModule.GetInputFile(context, out virtualPath, out qeryString);//这里跟那里是一样的
object[] obj = new object[] { };
Dictionary<string, string> qeryStringDictionary = new Dictionary<string, string>();
var receiveMembers = System.Web.Compilation.BuildManager.GetCompiledType(virtualPath).GetMember("ReceiveParameters");//获取访问当前页面的所有ReceiveParameters成员 (这个是我自己加的,就是想做成和mvc的那种模式,但可能不是很好)
System.Reflection.MethodInfo receiveParameters=null;
if (qeryString != null&&qeryString.Count>0)//如果查找到没有参数则不去反射了
{
foreach (System.Reflection.MemberInfo receiveMember in receiveMembers)//遍历所有ReceiveParameters成员
{
if (receiveMember.MemberType == System.Reflection.MemberTypes.Method)//因为上面获取到的是成员 但我们要的是方法所有要判断下
{
System.Reflection.MethodInfo methodInfo = receiveMember as System.Reflection.MethodInfo;
if (methodInfo != null)
{
var parameters = methodInfo.GetParameters();//获取ReceiveParameters方法的所有参数
int optionalCount = parameters.Count(i => i.IsOptional);//获取ReceiveParameters参数里面有多少个可选参数
bool b = qeryString.Count == parameters.Length - optionalCount;
if (qeryString.Count == parameters.Length || b)//如果当前查询的参数或ReceiveParameters的所有参数-去可选择的查询参数相等
{
receiveParameters = methodInfo;//记录这个方法
int i = 0;
obj = new object[parameters.Length];//记录参数值,到后面调用ReceiveParameters时用
for (; i < parameters.Length; i++)
{
string name = parameters[i].Name;//获取参数的名称
string value = string.Empty;
if (qeryString.Count > i)//如果ReceiveParameters参数没到可选参数那么则去查询的字符串
{
value = qeryString[i];
}
obj[i] = value;//把查询的字符串保存起来,到后面调用ReceiveParameters时用
qeryStringDictionary.Add(name, value);//添加到自定义的集合里面
}
break;
}
}
}
}
if (receiveParameters == null)//判断是否已经找到,如果没找到就把以前找的文件信息全部赋为重写的文件信息,也就是不存在的
{
virtualPath = context.Request.Path;
inputFile = context.Request.PhysicalPath;
}
}
var temp= System.Web.UI.PageParser.GetCompiledPageInstance(virtualPath, inputFile, context);//编译页面
if (receiveParameters != null)//这个里面的内容其实应该写到ReleaseHandler里面去的,但我写在这里了
{
System.Web.UI.Page page = (System.Web.UI.Page)temp;
page.Init+=new EventHandler(page_Init);//添加一个事件 ,//还有就是本来应该添加一个PageBase类的,那样就可以把真实的路径信息和查询参数放进去
sss = receiveParameters;
sssobj = obj;
//receiveParameters.Invoke(temp, obj);
}
return temp;
}
public System.Reflection.MethodInfo sss { get; set; }
public object[] sssobj { get; set; }
protected void page_Init(object sender, EventArgs e)
{
sss.Invoke(sender, sssobj);//当page执行到这里时就去调用ReceiveParameters方法 在这里还可以做其它的判断。。。 但不符合编程规范(我的理解)
}
///<summary>
/// 使工厂可以重用现有的处理程序实例
///</summary>
///<param name="handler">要重用的 System.Web.IHttpHandler 对象</param>
public void ReleaseHandler(IHttpHandler handler)
{
}
#endregion
}
}
页面代码就是多放几个方法
///<summary>
/// 一个参数的 如果需要多个则手动添加如public void ReceiveParameters(string name,string value)等等 这样页面编译后就会根据参数自动运行这个方法并转递参数值
///</summary>
///<param name="name">参数名称为name</param>
public void ReceiveParameters(string name)
{
var temp = Request;
}

url的解决了,在来看看干掉试图的。。。
我只写了把事件的实体状态去掉了,然后手动去激发控件的事件,而且就是在url中写里面解决的 代码如下:

复制代码 代码如下:

protected void page_Init(object sender, EventArgs e)
{
sss.Invoke(sender, sssobj);
Page page = (Page)sender;
foreach (string name in page.Request.Form.AllKeys)//查找form里面所有的字典 其实应该取__EVENTARGUMENT隐藏域的
{
try
{
System.Web.UI.Control control = page.FindControl(page.Page.Request.Form[name]);//查找这个控件
if (control != null)
{
string value = page.Request.Form[Page.postEventSourceID];
IPostBackEventHandler ip = control as IPostBackEventHandler;
if (ip != null)//能转换成IPostBackEventHandler 那么就激发它
{
ip.RaisePostBackEvent(value);
break;
}
IPostBackDataHandler backDataHandler = control as IPostBackDataHandler;
if (backDataHandler != null)//能转换成IPostBackDataHandler 就把__EVENTTARGET隐藏域的值传给控件 然后激发更改事件
{
System.Collections.Specialized.NameValueCollection nameValueCollection=new System.Collections.Specialized.NameValueCollection();
nameValueCollection.Add(page.Request.Form[control.ClientID],page.Request.Form[control.ClientID]);
backDataHandler.LoadPostData(control.ClientID, nameValueCollection);
backDataHandler.RaisePostDataChangedEvent();
}
}
break;
}
catch
{
}
}
}

这样简单的处理就完了,
我希望各位来帮我改进改进,因为我毕竟还不太了解ASp.net的处理机制。。。

时间: 2024-10-25 12:50:11

URL重写及干掉ASP.NET试图状态的实现方法_实用技巧的相关文章

asp.net用url重写URLReWriter实现任意二级域名第1/2页_实用技巧

好久没有写技术文章,如果大家看不明白,就多看几篇,汗,或者,在文章的后面回复(这是最有效的办法),我会尽力帮助大家解答疑惑. 来找这篇文章的,应该都知道什么叫二级域名吧,废话就不说了.但是讨论前,先要明白一个思想问题. 很多朋友一直考虑不清(我前几天也一直搞不明白)的问题是,我键入一个地址后,怎么这个url就被重写了? 第一步:在浏览器键入了一个地址,比如http://love.kerry.com,点回车后,都发生了什么? 为了把问题简单化,我来这样解释: 第二步:首先,键入的地址被解析,最终来

三种asp.net页面跳转的方法_实用技巧

第一种方法:response.redirect这个跳转页面的方法跳转的速度不快,因为它要走2个来回(2次postback),但它可以跳转到任何页面,没有站点页面限制(即可以由雅虎跳到新浪),同时不能跳过登录保护.但速度慢是其最大缺陷!redirect跳转机制:首先是发送一个http请求到客户端,通知需要跳转到新页面,然后客户端在发送跳转请求到服务器端.需要注意的是跳转后内部空间保存的所有数据信息将会丢失,所以需要用到session.代码如下  using System; using System

Asp.NET调用百度翻译的方法_实用技巧

本文实例讲述了Asp.NET调用百度翻译的方法.分享给大家供大家参考.具体分析如下: Asp.NET调用百度翻译,如下图所示: HTML代码如下: 复制代码 代码如下: <%@ Page Language="C#" AutoEventWireup="true" CodeFile="baidu.aspx.cs" Inherits="FanYi_baidu" %>  <!DOCTYPE html PUBLIC &

asp.net实现输出xml的方法_实用技巧

本文实例讲述了asp.net实现输出xml的方法.分享给大家供大家参考,具体如下: #region 根据xml节点 查询xml节点的值并作修改 /// <summary> /// 根据xml节点 查询xml节点的值并作修改 /// </summary> /// <param name="fileName">要加载的xml文件</param> /// <param name="tagName">xml节点的名

asp.net中调用存储过程的方法_实用技巧

本文实例讲述了asp.net中调用存储过程的方法.分享给大家供大家参考,具体如下: 一.建立并调用一个不带参数的存储过程如下: CREATE PROCEDURE 全部学生<dbo.selectUsers> AS SELECT * FROM 学生 GO EXEC 全部学生 建立并调用一个带参数的存储过程如下: CREATE PROCEDURE 学生查询1 @SNAME VARCHAR(8),@SDEPT VARCHAR(20) AS SELECT * FROM 学生 WHERE 姓名=@SNAM

ASP.NET显示渐变图片实现方法_实用技巧

先给大家来个最终效果: 实现效果,首先准备一张图片,高度为25pixel,宽度为1至3pixel渐变的图片.可以这里下载. 还要准备数据: Dictionary<int, int> Datas { get { Dictionary<int, int> d = new Dictionary<int, int>(); d.Add(1, 35); d.Add(2, 45); d.Add(3, 20); return d; } } ok,数据准备完了,在aspx里放三个Labe

ASP.NET使用TreeView显示文件的方法_实用技巧

本文实例讲述了ASP.NET使用TreeView显示文件的方法,是非常实用的技巧.分享给大家供大家参考.具体实现方法如下: 通常在ASP.NET中,TreeView的使用很普遍,这里详细讲述一下使用TreeView显示文件的方法. 1.首先加入TreeView控件: <asp:TreeView ID="driverInfoView" runat="server" ImageSet="XPFileExplorer" OnTreeNodePop

ASP.NET显示农历时间的方法_实用技巧

本文实例讲述了ASP.NET显示农历时间的方法.分享给大家供大家参考.具体实现方法如下: CS部分代码如下: 复制代码 代码如下: public string ChineseTimeNow = "";  public string ForignTimeNow = "";  private static ChineseLunisolarCalendar calendar = new ChineseLunisolarCalendar();  private static

asp.net简单生成验证码的方法_实用技巧

本文实例讲述了asp.net简单生成验证码的方法.分享给大家供大家参考,具体如下: 1.新建一个一般处理程序 namespace WebApplication1 { /// <summary> /// $codebehindclassname$ 的摘要说明 /// </summary> [WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfil