http://haacked.com/archive/2008/05/19/updated-routing-with-webforms.aspx
ASP.NET MVC 框架中包含了 Routing 的功能,由 System.Web.Routing 提供。但这个功能并不局限于 MVC,而且已经从中分离出来成为了一个独立的组件。
Phil Haack 的 blog 中提出一种办法可以配合 WebForm 使用 Routing 功能。这里有几个关键点。
首先,需要实现一个 IRouteHandler,它是一个 IHttpHandler 的提供者。
namespace System.Web.Routing
{
public interface IRouteHandler
{
IHttpHandler GetHttpHandler(RequestContext requestContext);
}
}
{
public interface IRouteHandler
{
IHttpHandler GetHttpHandler(RequestContext requestContext);
}
}
这里 Phil 创建实现了一个 WebFormRouteHandler. 其关键代码如下:
namespace WebFormRouting
{
public class WebFormRouteHandler : IRouteHandler
{
//
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
// 根据 RouteData 得到被替换后的虚拟路径
string virtualPath = GetSubstitutedVirtualPath(requestContext);
// 对 URL 进行身份验证(如果需要)
if (this.CheckPhysicalUrlAccess && !UrlAuthorizationModule.CheckUrlAccessForPrincipal(virtualPath, requestContext.HttpContext.User, requestContext.HttpContext.Request.HttpMethod))
throw new SecurityException();
// 根据虚拟路径创建 Page 对象
var page = BuildManager.CreateInstanceFromVirtualPath(virtualPath, typeof(Page)) as IHttpHandler;
if (page != null)
{
//Pages that don't implement IRoutablePage won't have the RequestContext
//available to them. Can't generate outgoing routing URLs without that context.
// 查看页面是否实现了 IRoutablePage (包含 RequestContext 属性,可产生出去的 routing URLs)
// 设置其 RequestContext
var routablePage = page as IRoutablePage;
if (routablePage != null)
routablePage.RequestContext = requestContext;
}
return page;
}
}
}
{
public class WebFormRouteHandler : IRouteHandler
{
//
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
// 根据 RouteData 得到被替换后的虚拟路径
string virtualPath = GetSubstitutedVirtualPath(requestContext);
// 对 URL 进行身份验证(如果需要)
if (this.CheckPhysicalUrlAccess && !UrlAuthorizationModule.CheckUrlAccessForPrincipal(virtualPath, requestContext.HttpContext.User, requestContext.HttpContext.Request.HttpMethod))
throw new SecurityException();
// 根据虚拟路径创建 Page 对象
var page = BuildManager.CreateInstanceFromVirtualPath(virtualPath, typeof(Page)) as IHttpHandler;
if (page != null)
{
//Pages that don't implement IRoutablePage won't have the RequestContext
//available to them. Can't generate outgoing routing URLs without that context.
// 查看页面是否实现了 IRoutablePage (包含 RequestContext 属性,可产生出去的 routing URLs)
// 设置其 RequestContext
var routablePage = page as IRoutablePage;
if (routablePage != null)
routablePage.RequestContext = requestContext;
}
return page;
}
}
}
在通过路由信息找到相关的 Page 后,能够通过 System.Web.Compilation.BuildManager 的 CreateInstanceFromVirtualPath 方法,接受一个虚拟路径和所需创建的 Page 类型,即可创建出相应的 Page 对象来处理请求。
我看了目前 ASP.NET MVC 框架的实现,其中默认的视图引擎 WebFormViewEngine 也是通过了这个方法来创建相关的 Page 对象。
需要注意的是,Routing 和 URL Rewrite 是有区别的,我的理解是 Routing 比 URL Rewrite 发生的更早,并不会在内部发起一个新的 Request.
因此 Phil 提到需要注意的一个安全问题,就是结合窗体身份验证时,如果不注意,Routing 会跳过身份验证这个环节的监测。因此,上面代码中的 UrlAuthorizationModule.CheckUrlAccessForPrincipal 方法调用就是对这个问题的补救。
同样基于这个区别的原因,Routing 的目标地址不可以带 QueryString 参数,变通的办法是可以通过 RouteData 传递参数。