您的位置:首页 > 编程语言 > ASP

ASP.NET查找路由表RouteTable中路由名等信息的方法

2015-08-18 21:40 861 查看
10年前使用的.NET 2.0需要升级了,要读读.NET Framework 4.5方面的技术书了。最近在看《精通ASP.NET 4.5》(第5版)中有关的路由技术时,发现列出路由表中映射的虚拟路径比较容易,但要找出映射的物理文件路径和路由名就比较麻烦。看到该书后面章节时,找到了路由表映射的物理文件文件路径。于是,使用Bing满世界查找,终于在一个论坛中找到了一个可行的方法

方法思路是:RouteTable.Routes的类型是RouteCollection,该类派生自Collection<RouteBase>,其中包含了一个不公开的Dictionary<string, RouteBase>字典成员,该字典就是一个路由名作为Key的路由字典。如何获得该字典成员是问题的关键。解决方法是:该字典成员使用了私有字段_namedMap(不知道原文作者是如何知道的,见本文的后记),通过反射技术可以获得字段成员。

1、路由配置(测试用)

下面的代码是一个路由表的设置情况,为简单见,把配置代码写在了全局应用程序类Global的隐藏代码文件Global.asax.cs中。

using System;
using System.Web.Routing;

namespace Test
{
public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
RouteTable.Routes.MapPageRoute(null, "null", "~/null.aspx");
RouteTable.Routes.MapPageRoute("", "empty", "~/empty.aspx");
RouteTable.Routes.MapPageRoute("test", "test", "~/test.aspx");
}
}
}
2、列表路由信息的网页部分(aspx部分)

下面代码是ListRouteItems.aspx的网页部分代码。

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ListRouteItems.aspx.cs" Inherits="Test.ListRouteItems" %>

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title></title>
</head>
<body>
<form id="form1" runat="server">
<table border="1">
<tr>
<td>Name</td>
<td>MappedPath</td>
<td>PhysicalPath</td>
</tr>

<asp:Repeater ID="RouteTable" ItemType="Test.RouteItem" SelectMethod="GetRouteItems" runat="server">
<ItemTemplate>
<tr>
<td><%# Item.Name %></td>
<td><%# Item.MappedPath %></td>
<td><%# Item.PhysicalPath %></td>
</tr>
</ItemTemplate>
</asp:Repeater>

</table>
</form>
</body>
</html>
3、列出路由名等信息的程序(aspx.cs部分)

下面代码是ListRouteItems.aspx的代码隐藏文件ListRouteItems.aspx.cs,其中包含了获得Dictionary<string, RouteBase>的代码和自定义结构体RouteItem。代码中可以看出,RouteCollection类的_namedMap私有字段保存了路由表字典(基本信息)。

using System.Collections.Generic;
using System.Web.Routing;
using System.Reflection;

namespace Test
{
public partial class ListRouteItems : System.Web.UI.Page
{
public IEnumerable<RouteItem> GetRouteItems()
{
var routeCollection = GetRouteCollection();  // 获得路由名为Key的字典

foreach (var route in System.Web.Routing.RouteTable.Routes)
{
Route r = route as Route;
if (r != null)
{
string name = GetRouteName(routeCollection, route);  // 获得路由名
PageRouteHandler p = r.RouteHandler as PageRouteHandler;  // 获得映射的物理文件路径
yield return new RouteItem { Name = name, MappedPath = r.Url, PhysicalPath = p.VirtualPath };
}
}
}

private Dictionary<string, RouteBase> GetRouteCollection()
{
var routes = System.Web.Routing.RouteTable.Routes;
var namedMapField = routes.GetType().GetField("_namedMap", BindingFlags.NonPublic | BindingFlags.Instance);
var collection = namedMapField.GetValue(routes) as Dictionary<string, RouteBase>;
return collection;
}

private string GetRouteName(Dictionary<string, RouteBase> collection, RouteBase route)
{
foreach (var item in collection)
{
if (item.Value == route)
{
return item.Key;
}
}

return "(null)";
}
}

public struct RouteItem
{
public string Name { get; set; }
public string MappedPath { get; set; }
public string PhysicalPath { get; set; }
}
}
4、ListRouteItems.aspx运行图

下图是网页程序运行情况。



结合上面网页图和代码ListRouteItems.aspx.cs知道,路由表中路由名null和""空串相同,且没有保存在RouteCollection的_nameMap字典中。

后记

仔细思考了为何原文作者知道RouteCollection有一个_namedMap字段的问题。进一步,即如何破解MS中类型定义未公开的秘密?答案是使用反射技术。例如如下代码就可以大致了解RouteCollection的字段成员,进而估计出该类有一个Dictionary<string, RouteBase>字典成员。

Type type = typeof(System.Web.Routing.RouteCollection);
FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
foreach (var fi in fields)
{
Console.WriteLine(fi.Name + "," + fi.FieldType.UnderlyingSystemType);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: