構建可讀性更高的 ASP.NET Core 路由

墨墨墨墨小宇發表於2019-05-31

 一、前言

  不知你在平時上網時有沒有注意到,絕大多數網站的 URL 地址都是小寫的英文字母,而我們使用 .NET/.NET Core MVC 開發的專案,因為在 C# 中類和方法名採用的是 Pascal 命名規範,根據 .NET 框架預設的路由規則,專案的 URL 地址會呈現出大小寫混合的情況。對於強迫症來說,這種情況絕對不能忍,當然,由於整個專案的 URL 地址大小寫混合顯示,也無法更清晰的向使用者、瀏覽器表達出當前頁面的功能。那麼,這篇文章就來介紹下,如何調整我們的 ASP.NET Core 專案的路由規則,從而使我們專案的 URL 地址可讀性更高。

  PS:在構建 URL 的過程中,採用大寫的地址還是採用小寫的地址,每個人都會有自己的想法和這樣做的理由,這篇文章不討論兩種方案的優劣,只是提供一種構建小寫 URL 地址以及讓我們的 URL 可讀性更高的解決方案,請友善觀看,切勿互懟。

  程式碼倉儲:https://github.com/Lanesra712/grapefruit-common

 二、Step by Step

  在構建專案的路由時,不管是採用大寫的 URL 路由,還是採用小寫的 URL 路由,我們首先需要確保的是,我們需要將整個專案的 URL 格式進行統一。不能說一個專案一部分的 URL 地址用大寫的,而另一部分採用的是小寫的 URL 地址。同時,同一個頁面的大寫的路徑以及小寫的路徑,雖然最終伺服器可能都會將兩個地址指向同一個頁面,但是對於搜尋引擎的收錄來說,這無疑是兩個頁面。

  試想以下,當別人告訴了我們一個有趣的網站,我們從瀏覽器的位址列中輸入網址進行訪問。當我們輸入 URL 地址時,不管是中文輸入法還是英文輸入法,輸出的英文字母都是小寫的,此時,如果輸入的網址中存在大寫字母,嗯,我們還需要使用 CapsLock 鍵進行大小寫切換。

  另外,我們知道,對於 Windows 伺服器來說,因為對於路徑的大小寫不敏感,如果我們弄錯了地址的大小寫,我們還是可以進行正常的訪問的,可是,如果將應用部署到 Linux 伺服器上的話。。。。

  至於更好的可讀性,這個概念可能會顯得有些主觀。簡單來說,就是當我們面對一個網址時,我們可以很清楚的通過這個網址知道這個網頁的主要內容。例如,當我們看見www.youdomain.com/editor/post/new 這個網址時,雖然可能並沒有開啟這個網頁,但我們還是可以大致猜到這個頁面可能是新增文章的。可是,如果你收到的網址是 www.youdomain.com/9rg7f2/i?HXI-D+iaj34 這樣的,沒人能知道這個頁面到底是幹啥的。

  因此,為了便捷輸入,首先我們需要將我們的 URL 地址轉換成小寫的形式,在 ASP.NET Core 中,微軟提供了 RoutingServiceCollectionExtensions.AddRouting 這個擴充套件方法可以讓我們將 URL 地址轉換成小寫。
  開啟專案的 Startup.cs 檔案,找到 ConfigureServices 方法,在方法體內新增下面的程式碼。

services.AddRouting(options =>
{
    options.LowercaseUrls = true;
});

  示例專案的頂部連結程式碼如下所示,執行專案可以看到,通過設定小寫路由後,程式根據 Controller 和 Action 自動生成的 URL 地址全部變成了小寫。仔細觀察可以發現,這裡會出現一個問題。在某些特殊的情況下,Area/Controller/Action 可能是由多個英文字母拼接而成的一個混合英文單詞,如果把這個混合的單詞全部進行小寫而不進行拆分的話,整個專案的 URL 可讀性更低了。

<header>
    <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
        <div class="container">
            <a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">Sample</a>
            <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                    aria-expanded="false" aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>
            <div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
                <ul class="navbar-nav flex-grow-1">
                    <li class="nav-item">
                        <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link text-dark" asp-area="" asp-controller="Post" asp-action="DraftSetting">Draft Setting</a>
                    </li>
                </ul>
            </div>
        </div>
    </nav>
</header>

  在 Startup 類中的 Configure 方法裡,我們定義了針對包含 Area 和不包含 Area 的兩個路由模板,整個專案的 URL 都是根據這兩個模板進行生成的。那麼這裡我們是不是可以通過對單個 Controller 或是 Action 指定特殊的 URL 格式呢?

app.UseMvc(routes =>
{
    routes.MapRoute(
        name: "default",
        template: "{controller=Home}/{action=Index}/{id?}");

    routes.MapRoute(
        name: "areas",
        template: "{area:exists}/{controller=Home}/{action=Index}/{id?}");
});

  答案當然是可以的。在 ASP.NET Core 中,我們可以通過在 Controller 或是 Action 方法上新增 RouteAttribute 的方式將使用者自定義路由資訊新增到專案的路由表中。例如這裡我在 DraftSetting 這個 Action 上使用特性路由的方式手動指定當前 Action 生成特殊的 URL 格式。 

public class PostController : Controller
{
    [Route("post/draft-setting")]
    public IActionResult DraftSetting()
    {
        return View();
    }
}

  雖然這樣可以解決我們的問題,可以一旦專案有新增頁面時,就要手動的指定特性路由地址,這樣似乎有些麻煩。那麼,如何自動的讓程式幫我們實現這一功能呢?

  在 ASP.NET Core 2.2 版本中,微軟為我們提供了引數轉換器這一概念,我們可以通過實現 IOutboundParameterTransformer 這個介面,從而將 URL 中路由的值或者是 URL 中路由引數的值按照我們的需求進行轉換。就像下面的程式碼中,我通過實現這個介面,從而實現將多個英文單詞生成的混合單詞以 hyphen(-) 的形式進行分隔。

public class SlugifyParameterTransformer : IOutboundParameterTransformer
{
    public string TransformOutbound(object value)
    {
        return value == null
            ? null
            : Regex.Replace(value.ToString(), "([a-z])([A-Z])", "$1-$2").ToLower();
    }
}

  這裡我使用 hyphen(-) 作為 URL 中各個單詞間的連字元,是因為對於搜尋引擎來說,它會將 - 視為單詞間分隔符,採用這種風格的 URL 更有利於搜尋引擎收錄。

  當介面功能實現之後,我們就需要對我們的預設全域性路由進行修改。首先,我們需要在路由模板上指定需要替換的路由引數,這裡我們指定 Area、Controller、Action 是需要進行路由引數轉換的變數。

app.UseMvc(routes =>
{
    routes.MapRoute(
        name: "default",
        template: "{controller:slugify=Home}/{action:slugify=Index}/{id?}");

    routes.MapRoute(
       name: "areas",
       template: "{area:exists:slugify}/{controller:slugify=Home}/{action:slugify=Index}/{id?}"
    );
});

  當定義好引數轉換器以及需要轉換的 URL 路由引數後,我們就可以在 AddRouting 方法中通過 ConstraintMap 進行配置需要轉換的引數路由值。至此就可以完成我們進行路由引數轉換的結果。

services.AddRouting(options => {
    options.ConstraintMap["slugify"] = typeof(SlugifyParameterTransformer);
    options.LowercaseUrls = true;
});

 

 三、總結

    在本章中,我們主要是調整了 ASP.NET Core 專案中的預設路由,從而使專案的 URL 地址具有更好的可讀性。通過使用小寫路由和 hyphen(-) 路由,只是構建可讀性更高的 URL 地址的第一步,在構建頁面時,我們更應該考慮的是如何使用少數的單詞就可以讓使用者清楚當前頁面的功能,更簡短,更易讀的 URL 不僅對於使用者,對於搜尋引擎也是更友好的。

相關文章