1. 程式人生 > 實用技巧 >.Net Core路由基礎

.Net Core路由基礎

路由負責將請求 URI 對映到終結點並向這些終結點排程傳入的請求。路由在應用中定義,並在應用啟動時進行配置。路由可以選擇從請求包含的 URL 中提取值,然後這些值便可用於處理請求。通過使用應用中的路由資訊,路由還能生成對映到終結點的 URL。

要在 ASP.NET Core 2.2 中使用最新路由方案,請在Startup.ConfigureServices中為 MVC 服務註冊指定相容性版本:

services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

EnableEndpointRouting選項確定路由是應在內部使用 ASP.NET Core 2.1 或更早版本的基於終結點的邏輯還是使用其基於IRouter的邏輯。相容性版本設定為 2.2 或更高版本時,預設值為true

將值設定為false以使用先前的路由邏輯:

services.AddMvc(options => options.EnableEndpointRouting = false)
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

路由基礎知識

大多數應用應選擇基本的描述性路由方案,讓 URL 有可讀性和意義。預設傳統路由{controller=Home}/{action=Index}/{id?}

  • 支援基本的描述性路由方案。
  • 是基於 UI 的應用的有用起點。

開發者通常在專業情況下使用特性路由或專用傳統路由嚮應用的高流量區域新增其他簡潔路由。專用情況示例包括:部落格和電子商務終結點。

Web API 應使用屬性路由,將應用功能建模為一組資源,其中操作是由 HTTP 謂詞表示。也就是說,對同一邏輯資源執行的許多操作(例如,GET 和 POST)都使用相同 URL。屬性路由提供了精心設計 API 的公共終結點佈局所需的控制級別。

藉助 URL 生成支援,無需通過硬編碼 URL 將應用關聯到一起,即可開發應用。此支援允許從基本路由配置入手,並在確定應用的資源佈局後修改路由。

路由使用“終結點”(Endpoint) 來表示應用中的邏輯終結點。

終結點定義用於處理請求的委託和任意元資料的集合。元資料用於實現橫切關注點,該實現基於附加到每個終結點的策略和配置。

路由系統具有以下特徵:

  • 路由模板語法用於通過標記化路由引數來定義路由。

  • 可以使用常規樣式和屬性樣式終結點配置。

  • IRouteConstraint用於確定 URL 引數是否包含給定的終結點約束的有效值。

  • 應用模型(如 MVC/Razor Pages)註冊其所有終結點,這些終結點具有可預測的路由方案實現。

  • 路由實現會在中介軟體管道中任何所需位置制定路由決策。

  • 路由中介軟體之後出現的中介軟體可以檢查路由中介軟體針對給定請求 URI 的終結點決策結果。

  • 可以在中介軟體管道中的任何位置列舉應用中的所有終結點。

  • 應用可根據終結點資訊使用路由生成 URL(例如,用於重定向或連結),從而避免硬編碼 URL,這有助於可維護性。

  • URL 生成是基於支援任意可擴充套件性的地址:

    • 可以使用依賴關係注入 (DI)在任意位置解析連結生成器 API (LinkGenerator) 以生成 URL。
    • 如果無法通過 DI 獲得連結生成器 API,則IUrlHelper會提供生成 URL 的方法。

路由模板

在我們生成的專案中有一個預設的模板,來匹配路由訪問到對的路徑:

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

大多數應用通過 MapRoute 或IRouteBuilder上定義的一種類似擴充套件方法來建立路由。任何IRouteBuilder擴充套件方法都會建立Route的例項並將其新增到路由集合中。MapRoute不接受路由處理程式引數。MapRoute僅新增由DefaultHandler處理的路由。

上面這個模板和URL的路徑匹配類似,例如訪問路徑 /Product/Detail/17 對應 Controller = Product 、action = Detail 、 id = 17,這邊 id 後面的問號表示可選引數是可空的,controller 和 action 等於= 後面表示預設值,訪問路徑為 / 即訪問這個預設值路徑,但是訪問預設路徑就不能傳遞 id 了,除非這樣 /Home/Index/3 。

如果我們系統中的 id 為整數,我們要求不能為字串,那麼我們可以用如下約束(約束有很多種可以按自己情況設定),也可以進行多個約束用冒號隔開,有多個約束存在需要滿足所有約束的哦:

{id:int} // {id:int:min(1)}

路由的匹配也可以用正則表示式匹配:

routeBuilder.MapRoute(
    "Track Package Route",
    "package/{operation:regex(^track|create$)}/{id:int}");

我們設定多個路由規則,自上而下以第一個匹配成功為準。

使用RouteBuilder

必須在Startup.Configure方法中配置路由:

services.AddRouting();

設定如下路由規則:

var trackPackageRouteHandler = new RouteHandler(context =>
{
    var routeValues = context.GetRouteData().Values;
    return context.Response.WriteAsync(
        $"Hello! Route values: {string.Join(", ", routeValues)}");
});

var routeBuilder = new RouteBuilder(app, trackPackageRouteHandler);

routeBuilder.MapRoute(
    "Track Package Route",
    "package/{operation:regex(^track|create$)}/{id:int}");

routeBuilder.MapGet("hello/{name}", context =>
{
    var name = context.GetRouteValue("name");
    // The route handler when HTTP GET "hello/<anything>" matches
    // To match HTTP GET "hello/<anything>/<anything>, 
    // use routeBuilder.MapGet("hello/{*name}"
    return context.Response.WriteAsync($"Hi, {name}!");
});

var routes = routeBuilder.Build();
app.UseRouter(routes);

下表顯示了具有給定 URI 的響應。

URI響應

/package/create/3

Hello!Route values: [operation, create], [id, 3]

/package/track/-3

Hello!Route values: [operation, track], [id, -3]

/package/track/-3/

Hello!Route values: [operation, track], [id, -3]

/package/track/

請求失敗,不匹配。

GET /hello/Joe

Hi, Joe!

POST /hello/Joe

請求失敗,僅匹配 HTTP GET。

GET /hello/Joe/Smith

請求失敗,不匹配。

Map[Verb]方法將使用約束來將路由限制為方法名稱中的 HTTP 謂詞,像是 MapGet 表示匹配 Get 請求。RouteBuilder 不限於上面演示的,還有 MapDelete 等方法。

保留的路由名稱

以下關鍵字是保留的名稱,它們不能用作路由名稱或引數:

    • action
    • area
    • controller
    • handler
    • page

路由的資料令牌

URL 匹配是路由向終結點排程傳入請求的過程。此過程基於 URL 路徑中的資料,但可以進行擴充套件以考慮請求中的任何資料。向單獨的處理程式排程請求的功能是縮放應用的大小和複雜性的關鍵。

終結點路由中的路由系統負責所有的排程決策。由於中介軟體是基於所選終結點來應用策略,因此任何可能影響排程或安全策略應用的決策都應在路由系統內部制定,這一點很重要。

執行終結點委託時,將根據迄今執行的請求處理將RouteContext.RouteData的屬性設為適當的值。

RouteData.Values是從路由中生成的路由值的字典。這些值通常通過標記 URL 來確定,可用來接受使用者輸入,或者在應用內作出進一步的排程決策。

RouteData.DataTokens是一個與匹配的路由相關的其他資料的屬性包。提供DataTokens以支援將狀態資料與每個路由相關聯,以便應用可根據所匹配的路由作出決策。這些值是開發者定義的,不會影響通過任何方式路由的行為。此外,儲存於RouteData.DataTokens中的值可以屬於任何型別,與RouteData.Values相反,後者必須能夠轉換為字串,或從字串進行轉換。

RouteData.Routers是參與成功匹配請求的路由的列表。路由可以相互巢狀。Routers屬性可以通過導致匹配的邏輯路由樹反映該路徑。通常情況下,Routers中的第一項是路由集合,應該用於生成 URL。Routers中的最後一項是匹配的路由處理程式。

routes.MapRoute(
    name: "us_english_products",
    template: "en-US/Products/{id}",
    defaults: new { controller = "Products", action = "Details" },
    constraints: new { id = new IntRouteConstraint() },
    dataTokens: new { locale = "en-US" });

可以看到RouteData的資料為: