ASP.NET WebForms 自动路由所有页面 (AutoRoute)
轻松地用一行代码路由所有页面。
引言
在 ASP.NET 中,有几个因素会影响 URL 的路径。
为了组织页面,通常会将它们分组到文件夹中。
这是一个典型的页面 URL 示例。
/pages/admin/setup/user/v2/EditUser.aspx
页面 "EditUser.aspx" 位于 "pages" 文件夹中,该文件夹位于 "admin" 文件夹中,该文件夹位于 "setup" 文件夹中,该文件夹位于 "user" 文件夹中,该文件夹位于 "v2" 文件夹中…… 再次位于另一个名为 "pages" 的文件夹中。
随着项目规模的扩大,越来越多的根文件夹会散布在项目中的各个位置。
由于文件夹路径与文件的 URL 路径严格相关,这会导致 URL 变得非常长。
ASP.NET 提供了一个有用的函数调用 "路由 (Routing)",可以解决 URL 过长的问题。
以下是实现方法。
在项目的根目录下,添加一个 "全局应用程序类 (Global Application Class)" 文件,即 "Global.asax"。
打开 "Global.asax" 文件。
通过添加 using
语句导入路由库。
using System.Web.Routing;
在 Application_Start
方法中
protected void Application_Start(object sender, EventArgs e)
{
}
输入路由代码
protected void Application_Start(object sender, EventArgs e)
{
RouteTable.Routes.MapPageRoute("EditUser", "EditUser",
"~/admin/setup/user/v2/EditUser.aspx");
}
这将使以下 URL
/admin/setup/user/v2/EditUser.aspx
缩短为
/EditUser
到目前为止,看起来不错……
如果…… 有很多(是的…… 很多很多)页面怎么办?
好吧,最终你将需要逐个路由它们…… 例如
RouteTable.Routes.MapPageRoute("UserEdit", "UserEdit",
"~/admin/setup/user/v2/UserEdit.aspx");
RouteTable.Routes.MapPageRoute("UserList", "UserList",
"~/admin/setup/user/v2/UserList.aspx");
RouteTable.Routes.MapPageRoute("UserCategory", "UserCategory",
"~/admin/setup/user/v2/UserCategory.aspx");
RouteTable.Routes.MapPageRoute("UserCategoryEdit", "UserCategoryEdit",
"~/admin/setup/user/v2/UserCategoryEdit.aspx");
RouteTable.Routes.MapPageRoute("InvoicePreview", "InvoicePreview",
"~/invoice/user/v3/InvoicePreview.aspx");
RouteTable.Routes.MapPageRoute("InvoiceSarch", "InvoiceSarch",
"~/invoice/user/v3/InvoiceSarch.aspx");
// ...
// continue for yet another lots of... lots of pages...
// ....
是的,你明白了。这将需要大量的代码行。大量的路由代码会使维护工作变得痛苦。很难监控错误。
但是,如果…… 可以用一行代码自动路由所有页面呢?
我们要做的是
仅使用一个根文件夹来组织所有页面。
例如,不要像这样拥有多个根文件夹
/settings
/user
/activity
/invoice
/member
/inventory
....
而是将它们全部放在一个文件夹中,如下所示
/pages/settings
/pages/user
/pages/activity
/pages/invoice
/pages/member
/pages/inventory
然后,返回 "Global.asax" 文件来编写路由命令。
在 Application_Start
方法中,输入以下路由命令
protected void Application_Start(object sender, EventArgs e)
{
RouteFolder("~/pages");
}
以下是 RouteFolder
方法的内容
public static void RouteFolder(string folder)
{
// Obtain the root directory path:
// example: D:\wwwroot\mywebsite\
string rootFolder = HttpContext.Current.Server.MapPath("~/");
// ensure the "folder" is prefixed with "~/"
if (folder.StartsWith("~/"))
{ }
else if (folder.StartsWith("/"))
{
folder = "~" + folder;
}
else
{
folder = "~/" + folder;
}
// obtain the physical folder path
// example: D:\wwwroot\mywebsite\pages\
folder = HttpContext.Current.Server.MapPath(folder);
// Start routing the in another separate method
MapPageRoute(folder, rootFolder);
}
MapPageRoute
方法。首先获取子文件夹
static void MapPageRoute(string folder, string rootFolder)
{
// obtain sub-folders within the 'folder' directory
string[] folders = Directory.GetDirectories(folder);
// loop through each sub-folder
foreach (var subFolder in folders)
{
// perform a recursive loop call on every sub-folder
MapPageRoute(subFolder, rootFolder);
}
// obtain all files within the 'folder' directory
string[] files = Directory.GetFiles(folder);
// loop through each file
foreach (var file in files)
{
// if the file is an asp.net web page, skip the file
if (!file.EndsWith(".aspx"))
continue;
// convert the file path into web-relative path
// example:
// input >> D:\wwwroot\mywebsite\pages\Member.aspx
// output >> ~/pages/Member.aspx
string webPath = file.Replace(rootFolder, "~/").Replace("\\", "/");
// extract the filename without the extension from the file path
// example:
// input >> D:\wwwroot\mywebsite\pages\Member.aspx
// output >> Member
var filename = Path.GetFileNameWithoutExtension(file);
// check if the file belons to default landing page
// this file usually existed multiple times within a website
if (filename.ToLower() == "default")
{
// skip routing for the default landing page
continue;
}
// finally, perform the routing mechanism
// example of input:
// filename = Member
// webPath = ~/pages/Member.aspx
RouteTable.Routes.MapPageRoute(filename, filename, webPath);
}
}
所以现在,不要这样做
protected void Application_Start(object sender, EventArgs e)
{
RouteTable.Routes.MapPageRoute("UserEdit", "UserEdit",
"~/pages/admin/setup/user/v2/UserEdit.aspx");
RouteTable.Routes.MapPageRoute("UserList", "UserList",
"~/pages/admin/setup/user/v2/UserList.aspx");
RouteTable.Routes.MapPageRoute("UserCategory", "UserCategory",
"~/pages/admin/setup/user/v2/UserCategory.aspx");
RouteTable.Routes.MapPageRoute("UserCategoryEdit", "UserCategoryEdit",
"~/pages/admin/setup/user/v2/UserCategoryEdit.aspx");
RouteTable.Routes.MapPageRoute("InvoicePreview", "InvoicePreview",
"~/pages/invoice/user/v3/InvoicePreview.aspx");
RouteTable.Routes.MapPageRoute("InvoiceSarch", "InvoiceSarch",
"~/pages/invoice/user/v3/InvoiceSarch.aspx");
// ...
// continue for yet another lots of... lots of pages...
// ....
}
你只需要一行代码
protected void Application_Start(object sender, EventArgs e)
{
RouteFolder("~/pages");
}
瞧!完成了,就像魔术一样。所有页面都在没有人工干预的情况下完成了路由(逐个编写路由命令)。
所有这些具有令人困惑、复杂的 URL 路径的页面(由于页面组织方式)
/pages/admin/setup/user/v2/EditUser.aspx
/pages/admin/system/settings/AppConfig.aspx
/pages/user/ViewUserProfile.aspx
/pages/activity/ActivityEventList.aspx
/pages/invoice/v3/PrintInvoice.aspx
/pages/member/group/EditMemberList.aspx
/pages/departments/inventory/setup/InventoryCategory.aspx
现在都将缩短为
/EditUser
/AppConfig
/ViewUserProfile
/ActivityEventList
/PrintInvoice
/EditMemberList
/InventoryCategory
你只需要小心不要在不同的文件夹中重复(重用)相同的文件名。
例如(不要这样做)
/pages/member/Search.aspx
/pages/team/Search.aspx
而是将部分名称放在文件名中,如下所示
/pages/member/SearchMember.aspx
/pages/team/SearchTeam.aspx
页面将按如下方式路由
/SearchMember
/SearchTeam
好了,这篇文章就到此为止。
感谢阅读,祝您编码愉快。
历史
- 2022年11月14日:初始版本