65.9K
CodeProject 正在变化。 阅读更多。
Home

ASP.NET WebForms 自动路由所有页面 (AutoRoute)

starIconstarIconstarIconstarIconstarIcon

5.00/5 (7投票s)

2022年11月14日

CPOL

2分钟阅读

viewsIcon

7707

downloadIcon

157

轻松地用一行代码路由所有页面。

引言

在 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日:初始版本
© . All rights reserved.