终于开始了我的博客之旅。虽然之前注册过博客,但总是畏首畏尾的,一直处于空白状态。最近受好友启发,想想还是应该记录下自己的学习过程和心得体会,于己于人都有帮助。
最近在调查.NET Framework 3.5 SP1的新功能,顺便记录下来。
一.ASP.NET Routing(代码下载)
为了给用户提供一个清晰干净的Url地址,需要把冗长的复杂的Url地址隐藏起来,使其对用户不可见。之前可以通过“Url重写”,截取Url请求并将该请求重新定向到指定的Url,复杂的Url匹配需要用到正则表达式,而ASP.NET Routing则提供了更加简单舒适的Url重写功能。
利用ASP.NET Routing可以定位到任何ASP.NET资源,包括WebForms,ASMX services,Dynamic Data和MVC。
从上图可以看到,URL Routing Module会捕获请求,并查找Route Table中所有的Route,如果找到和该请求的Url相匹配的Route,则获取该Route的Route Handler,Route Handler会生成相应的HTTP Handler来响应请求。
应用ASP.NET Routing主要包括两个步骤:
1.自定义Route并将其注册到RouteTable中。RouteTable中储存了该应用程序注册过的所有的Url Route。
2.实现IRouteHandler接口,将处理对应Url的IHttpHandler返回。
首先新建一个项目,选择模板:ASP.NET Web应用程序,命名为MyRouting。使用ASP.NET Routing需要添加System.Web.Routing引用。打开Web.config文件,在<httpModules>中添加:
Web.config
<add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
选择添加新项->全局应用程序类,在Application_Start方法中定义Route并把它注册到RouteTable中。一般情况下都可以使用Route类来定义routes,但也可以通过继承Route类或RouteBase类来扩展其功能。
Global.asax
public class Global : System.Web.HttpApplication
{
void Application_Start(object sender, EventArgs e)
{
RegisterRoutes(RouteTable.Routes);
}
public static void RegisterRoutes(RouteCollection routes)
{
Route university = new Route("{table}/Details.aspx", new CustomRouteHandler()); // folder of University,{table} = "Students"/"Teachers".
routes.Add(university);
Route products = new Route("{ProductName}/{id}", new CustomRouteHandler()); // folder of Products,{ProductName} = "bikes"/"cars".
routes.Add(products);
Route serviceRoute = new Route("{WebServiceName}.asmx", new CustomRouteHandler()); // folder of WebServices,{WebServiceName} = "EntoRMB"/"RMBtoEn".
routes.Add(serviceRoute);
Route test = new Route("{test}", new CustomRouteHandler("~/Pages/Test/Test.aspx")); // folder of Test,{test} = anything.
routes.Add(test);
}
}
上面就实现了第一步,下面就要实现IRouteHandler接口。
添加一个类,命名为CustomRouteHandler,实现IRouteHandler接口,主要的任务就是获取或生成一个IHttpHandler,即实现GetHttpHandler方法。
如果是定位到aspx页面,自然是返回一个Page对象。但如果是定位到asmx service,由于WebService并没有实现IHttpHandler接口,因此不可能返回一个WebService对象。我所理解的是:ASP.NET Routing在这里只是起了URL地址重新定向的作用,即定位到满足Routing规则的WebService,至于最后的响应结果以什么形式表现出来,应该可以自己定义。我这里还是返回的Page对象。
CustomRouteHandler.cs
public class CustomRouteHandler : IRouteHandler
{
public CustomRouteHandler()
{
}
public CustomRouteHandler(string virtualPath)
{
this.VirtualPath = virtualPath;
}
public string VirtualPath { get; private set; }
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
foreach (var value in requestContext.RouteData.Values)
{
requestContext.HttpContext.Items[value.Key] = value.Value; // Items[table] = {table}; Items[ProductName] = {ProductName};
// Items[id] = {id}; Items[test] = {test}
}
try
{
if (VirtualPath != null)
{
return (IHttpHandler)BuildManager.CreateInstanceFromVirtualPath(VirtualPath, typeof(Page));
}
else
{
RouteBase thisRoute = requestContext.RouteData.Route;
RouteBase r1 = RouteTable.Routes[0]; // "{table}/Details.aspx"
RouteBase r2 = RouteTable.Routes[1]; // "{ProductName}/{id}"
RouteBase r3 = RouteTable.Routes[2]; // "Convert.asmx"
string actualPath = "";
if (thisRoute.Equals(r1))
{
actualPath = "~/Pages/University/" + RouteTable.Routes.GetVirtualPath(requestContext, requestContext.RouteData.Values).VirtualPath;
}
else if (thisRoute.Equals(r2))
{
actualPath = "~/Pages/Products/" + RouteTable.Routes.GetVirtualPath(requestContext, requestContext.RouteData.Values).VirtualPath;
actualPath = actualPath.Remove(actualPath.LastIndexOf("/")); // file path doesn't include information of id
string productName = requestContext.RouteData.GetRequiredString("ProductName");
if (productName.Equals("bikes"))
{
actualPath += "/bike.aspx"; // file path is bikes/bike.aspx
}
else if (productName.Equals("cars"))
{
actualPath += "/car.aspx"; // file path is cars/car.aspx
}
}
else if (thisRoute.Equals(r3))
{
string webServiceName = requestContext.RouteData.GetRequiredString("WebServiceName");
if (webServiceName.Equals("EntoRMB"))
{
actualPath = "/Pages/WebServices/ConvertEntoRMB.aspx";
}
else if (webServiceName.Equals("RMBtoEn"))
{
actualPath = "/Pages/WebServices/ConvertRMBtoEn.aspx";
}
}
return (IHttpHandler)BuildManager.CreateInstanceFromVirtualPath(actualPath, typeof(Page));
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return (IHttpHandler)BuildManager.CreateInstanceFromVirtualPath("~/Error.aspx", typeof(Page));
}
}
}