ASP.NET Core 中的路由Routing in ASP.NET Core

By Ryan NowakKirk LarkinRick AndersonBy Ryan Nowak, Kirk Larkin, and Rick Anderson

路由會負責比對傳入 HTTP 要求,並將這些要求分派至應用程式的可執行端點。Routing is responsible for matching incoming HTTP requests and dispatching those requests to the app's executable endpoints. 端點是應用程式的可執行要求處理常式代碼單位。Endpoints are the app's units of executable request-handling code. 端點會在應用程式中定義,並在應用程式啟動時設定。Endpoints are defined in the app and configured when the app starts. 端點比對程式可以從要求的 URL 中解壓縮值,並提供這些值來進行要求處理。The endpoint matching process can extract values from the request's URL and provide those values for request processing. 使用來自應用程式的端點資訊,路由也能夠產生對應至端點的 Url。Using endpoint information from the app, routing is also able to generate URLs that map to endpoints.

應用程式可以使用下列內容來設定路由:Apps can configure routing using:

  • 控制器Controllers
  • Razor頁面 Pages
  • SignalR
  • gRPC 服務gRPC Services
  • 端點啟用的中介軟體,例如健康情況檢查Endpoint-enabled middleware such as Health Checks.
  • 已向路由註冊的委派和 lambda。Delegates and lambdas registered with routing.

本檔涵蓋 ASP.NET Core 路由的低層級詳細資料。This document covers low-level details of ASP.NET Core routing. 如需設定路由的詳細資訊:For information on configuring routing:

本檔中所述的端點路由系統適用于 ASP.NET Core 3.0 和更新版本。The endpoint routing system described in this document applies to ASP.NET Core 3.0 and later. 如需以為基礎的先前路由系統的詳細資訊 IRouter ,請使用下列其中一種方法來選取 ASP.NET Core 2.1 版本:For information on the previous routing system based on IRouter, select the ASP.NET Core 2.1 version using one of the following approaches:

查看或下載範例程式碼 (如何下載) View or download sample code (how to download)

此檔的下載範例會由特定 Startup 類別啟用。The download samples for this document are enabled by a specific Startup class. 若要執行特定的範例,請修改Program.cs以呼叫所需的 Startup 類別。To run a specific sample, modify Program.cs to call the desired Startup class.

路由的基本概念Routing basics

所有 ASP.NET Core 範本都會在產生的程式碼中包含路由。All ASP.NET Core templates include routing in the generated code. 路由是在的中介軟體管線中註冊 Startup.ConfigureRouting is registered in the middleware pipeline in Startup.Configure.

下列程式碼顯示路由的基本範例:The following code shows a basic example of routing:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapGet("/", async context =>
        {
            await context.Response.WriteAsync("Hello World!");
        });
    });
}

路由會使用一對由和註冊的中介軟體 UseRouting UseEndpointsRouting uses a pair of middleware, registered by UseRouting and UseEndpoints:

  • UseRouting將路由對應新增至中介軟體管線。UseRouting adds route matching to the middleware pipeline. 此中介軟體會查看應用程式中定義的端點集合,並根據要求選取最符合的項This middleware looks at the set of endpoints defined in the app, and selects the best match based on the request.
  • UseEndpoints將端點執行新增至中介軟體管線。UseEndpoints adds endpoint execution to the middleware pipeline. 它會執行與所選端點相關聯的委派。It runs the delegate associated with the selected endpoint.

上述範例包含使用MapGet方法對程式碼端點的單一路由:The preceding example includes a single route to code endpoint using the MapGet method:

  • 當 HTTP GET 要求傳送至根 URL 時 /When an HTTP GET request is sent to the root URL /:
    • 所顯示的要求委派會執行。The request delegate shown executes.
    • Hello World!會寫入 HTTP 回應。Hello World! is written to the HTTP response. 根據預設,根 URL /https://localhost:5001/By default, the root URL / is https://localhost:5001/.
  • 如果要求方法不是 GET ,或根 URL 不是 / ,則不會符合任何路由,且會傳回 HTTP 404。If the request method is not GET or the root URL is not /, no route matches and an HTTP 404 is returned.

端點Endpoint

MapGet方法是用來定義端點The MapGet method is used to define an endpoint. 端點可以是:An endpoint is something that can be:

  • 已選取,藉由比對 URL 和 HTTP 方法。Selected, by matching the URL and HTTP method.
  • 執行委派。Executed, by running the delegate.

應用程式可比對並執行的端點會在中設定 UseEndpointsEndpoints that can be matched and executed by the app are configured in UseEndpoints. 例如,、 MapGet MapPost 和類似的方法會將要求委派連接至路由系統。For example, MapGet, MapPost, and similar methods connect request delegates to the routing system. 您可以使用其他方法,將 ASP.NET Core framework 功能連接到路由系統:Additional methods can be used to connect ASP.NET Core framework features to the routing system:

下列範例顯示具有更複雜路由範本的路由:The following example shows routing with a more sophisticated route template:

app.UseEndpoints(endpoints =>
{
    endpoints.MapGet("/hello/{name:alpha}", async context =>
    {
        var name = context.Request.RouteValues["name"];
        await context.Response.WriteAsync($"Hello {name}!");
    });
});

此字串 /hello/{name:alpha}路由範本The string /hello/{name:alpha} is a route template. 它是用來設定端點的相符方式。It is used to configure how the endpoint is matched. 在此情況下,範本會符合:In this case, the template matches:

  • URL,例如/hello/RyanA URL like /hello/Ryan
  • 開頭為的任何 URL 路徑, /hello/ 後面接著一連串的字母字元。Any URL path that begins with /hello/ followed by a sequence of alphabetic characters. :alpha套用僅符合字母字元的路由條件約束。:alpha applies a route constraint that matches only alphabetic characters. 本檔稍後會說明路由條件約束Route constraints are explained later in this document.

URL 路徑的第二個區段 {name:alpha}The second segment of the URL path, {name:alpha}:

本檔中所述的端點路由系統是 ASP.NET Core 3.0 的新功能。The endpoint routing system described in this document is new as of ASP.NET Core 3.0. 不過,ASP.NET Core 的所有版本都支援一組相同的路由範本功能和路由條件約束。However, all versions of ASP.NET Core support the same set of route template features and route constraints.

下列範例顯示具有健康情況檢查和授權的路由:The following example shows routing with health checks and authorization:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    // Matches request to an endpoint.
    app.UseRouting();

    // Endpoint aware middleware. 
    // Middleware can use metadata from the matched endpoint.
    app.UseAuthentication();
    app.UseAuthorization();

    // Execute the matched endpoint.
    app.UseEndpoints(endpoints =>
    {
        // Configure the Health Check endpoint and require an authorized user.
        endpoints.MapHealthChecks("/healthz").RequireAuthorization();

        // Configure another endpoint, no authorization requirements.
        endpoints.MapGet("/", async context =>
        {
            await context.Response.WriteAsync("Hello World!");
        });
    });
}

如果您想要查看翻譯成英文以外語言的程式碼批註,請在此 GitHub 討論問題中讓我們知道。If you would like to see code comments translated to languages other than English, let us know in this GitHub discussion issue.

上述範例示範如何:The preceding example demonstrates how:

  • 授權中介軟體可以與路由搭配使用。The authorization middleware can be used with routing.
  • 端點可以用來設定授權行為。Endpoints can be used to configure authorization behavior.

MapHealthChecks呼叫會新增健康情況檢查端點。The MapHealthChecks call adds a health check endpoint. 此呼叫的連結會將 RequireAuthorization 授權原則附加至端點。Chaining RequireAuthorization on to this call attaches an authorization policy to the endpoint.

呼叫 UseAuthenticationUseAuthorization 新增驗證和授權中介軟體。Calling UseAuthentication and UseAuthorization adds the authentication and authorization middleware. 這些中介軟體會放在 UseRouting 和之間 UseEndpoints ,使其可以:These middleware are placed between UseRouting and UseEndpoints so that they can:

  • 查看所選取的端點 UseRoutingSee which endpoint was selected by UseRouting.
  • 將分派給端點之前,請先套用授權原則 UseEndpointsApply an authorization policy before UseEndpoints dispatches to the endpoint.

端點中繼資料Endpoint metadata

在上述範例中,有兩個端點,但只有健全狀況檢查端點已附加授權原則。In the preceding example, there are two endpoints, but only the health check endpoint has an authorization policy attached. 如果要求符合健康狀態檢查端點, /healthz 則會執行授權檢查。If the request matches the health check endpoint, /healthz, an authorization check is performed. 這會示範端點可以附加額外的資料。This demonstrates that endpoints can have extra data attached to them. 這種額外的資料稱為端點中繼資料This extra data is called endpoint metadata:

  • 可由路由感知中介軟體處理中繼資料。The metadata can be processed by routing-aware middleware.
  • 中繼資料可以是任何 .NET 型別。The metadata can be of any .NET type.

路由概念Routing concepts

路由系統會藉由新增強大的端點概念,在中介軟體管線之上建立。The routing system builds on top of the middleware pipeline by adding the powerful endpoint concept. 端點代表應用程式功能的單位,在路由、授權及任何數目的 ASP.NET Core 系統之間彼此不同。Endpoints represent units of the app's functionality that are distinct from each other in terms of routing, authorization, and any number of ASP.NET Core's systems.

ASP.NET Core 端點定義ASP.NET Core endpoint definition

ASP.NET Core 的端點為:An ASP.NET Core endpoint is:

下列程式碼示範如何抓取和檢查符合目前要求的端點:The following code shows how to retrieve and inspect the endpoint matching the current request:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseRouting();

    app.Use(next => context =>
    {
        var endpoint = context.GetEndpoint();
        if (endpoint is null)
        {
            return Task.CompletedTask;
        }
        
        Console.WriteLine($"Endpoint: {endpoint.DisplayName}");

        if (endpoint is RouteEndpoint routeEndpoint)
        {
            Console.WriteLine("Endpoint has route pattern: " +
                routeEndpoint.RoutePattern.RawText);
        }

        foreach (var metadata in endpoint.Metadata)
        {
            Console.WriteLine($"Endpoint has metadata: {metadata}");
        }

        return Task.CompletedTask;
    });

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapGet("/", async context =>
        {
            await context.Response.WriteAsync("Hello World!");
        });
    });
}

若已選取,則可以從抓取端點 HttpContextThe endpoint, if selected, can be retrieved from the HttpContext. 可以檢查其屬性。Its properties can be inspected. 端點物件是不可變的,而且無法在建立之後修改。Endpoint objects are immutable and cannot be modified after creation. 最常見的端點類型是 RouteEndpointThe most common type of endpoint is a RouteEndpoint. RouteEndpoint包含可讓路由系統選取的資訊。RouteEndpoint includes information that allows it to be to selected by the routing system.

在上述程式碼中, app。使用會設定內嵌中介軟體In the preceding code, app.Use configures an in-line middleware.

下列程式碼顯示,視管線中呼叫的位置而定, app.Use 可能不會有端點:The following code shows that, depending on where app.Use is called in the pipeline, there may not be an endpoint:

// Location 1: before routing runs, endpoint is always null here
app.Use(next => context =>
{
    Console.WriteLine($"1. Endpoint: {context.GetEndpoint()?.DisplayName ?? "(null)"}");
    return next(context);
});

app.UseRouting();

// Location 2: after routing runs, endpoint will be non-null if routing found a match
app.Use(next => context =>
{
    Console.WriteLine($"2. Endpoint: {context.GetEndpoint()?.DisplayName ?? "(null)"}");
    return next(context);
});

app.UseEndpoints(endpoints =>
{
    // Location 3: runs when this endpoint matches
    endpoints.MapGet("/", context =>
    {
        Console.WriteLine(
            $"3. Endpoint: {context.GetEndpoint()?.DisplayName ?? "(null)"}");
        return Task.CompletedTask;
    }).WithDisplayName("Hello");
});

// Location 4: runs after UseEndpoints - will only run if there was no match
app.Use(next => context =>
{
    Console.WriteLine($"4. Endpoint: {context.GetEndpoint()?.DisplayName ?? "(null)"}");
    return next(context);
});

先前 Console.WriteLine 的範例會加入語句,以顯示是否已選取端點。This preceding sample adds Console.WriteLine statements that display whether or not an endpoint has been selected. 為了清楚起見,此範例會將顯示名稱指派給提供的 / 端點。For clarity, the sample assigns a display name to the provided / endpoint.

以顯示的 URL 執行此程式碼 /Running this code with a URL of / displays:

1. Endpoint: (null)
2. Endpoint: Hello
3. Endpoint: Hello

執行此程式碼時,會顯示任何其他 URL:Running this code with any other URL displays:

1. Endpoint: (null)
2. Endpoint: (null)
4. Endpoint: (null)

此輸出示範:This output demonstrates that:

  • 在呼叫之前,端點一律為 null UseRoutingThe endpoint is always null before UseRouting is called.
  • 如果找到相符的,則與之間的端點為非 null UseRouting UseEndpointsIf a match is found, the endpoint is non-null between UseRouting and UseEndpoints.
  • UseEndpoints當找到相符的時,中介軟體就是終端機。The UseEndpoints middleware is terminal when a match is found. 終端機中介軟體會在本檔稍後定義。Terminal middleware is defined later in this document.
  • UseEndpoints只有當找不到相符的時,才會在執行後中介軟體。The middleware after UseEndpoints execute only when no match is found.

UseRouting中介軟體會使用task.setendpoint方法,將端點附加至目前的內容。The UseRouting middleware uses the SetEndpoint method to attach the endpoint to the current context. 您可以 UseRouting 使用自訂邏輯來取代中介軟體,但仍可獲得使用端點的優點。It's possible to replace the UseRouting middleware with custom logic and still get the benefits of using endpoints. 端點是低層級的基本型別,例如中介軟體,而且不會與路由執行結合。Endpoints are a low-level primitive like middleware, and aren't coupled to the routing implementation. 大部分的應用程式不需要以 UseRouting 自訂邏輯取代。Most apps don't need to replace UseRouting with custom logic.

UseEndpoints中介軟體是設計用來與中介軟體一起使用 UseRoutingThe UseEndpoints middleware is designed to be used in tandem with the UseRouting middleware. 執行端點的核心邏輯並不複雜。The core logic to execute an endpoint isn't complicated. 使用 GetEndpoint 來取出端點,然後叫用其 RequestDelegate 屬性。Use GetEndpoint to retrieve the endpoint, and then invoke its RequestDelegate property.

下列程式碼示範中介軟體會如何影響或回應路由:The following code demonstrates how middleware can influence or react to routing:

public class IntegratedMiddlewareStartup
{ 
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        // Location 1: Before routing runs. Can influence request before routing runs.
        app.UseHttpMethodOverride();

        app.UseRouting();

        // Location 2: After routing runs. Middleware can match based on metadata.
        app.Use(next => context =>
        {
            var endpoint = context.GetEndpoint();
            if (endpoint?.Metadata.GetMetadata<AuditPolicyAttribute>()?.NeedsAudit
                                                                            == true)
            {
                Console.WriteLine($"ACCESS TO SENSITIVE DATA AT: {DateTime.UtcNow}");
            }

            return next(context);
        });

        app.UseEndpoints(endpoints =>
        {         
            endpoints.MapGet("/", async context =>
            {
                await context.Response.WriteAsync("Hello world!");
            });

            // Using metadata to configure the audit policy.
            endpoints.MapGet("/sensitive", async context =>
            {
                await context.Response.WriteAsync("sensitive data");
            })
            .WithMetadata(new AuditPolicyAttribute(needsAudit: true));
        });

    } 
}

public class AuditPolicyAttribute : Attribute
{
    public AuditPolicyAttribute(bool needsAudit)
    {
        NeedsAudit = needsAudit;
    }

    public bool NeedsAudit { get; }
}

上述範例示範兩個重要概念:The preceding example demonstrates two important concepts:

  • 中介軟體可以在前執行, UseRouting 以修改路由運作的資料。Middleware can run before UseRouting to modify the data that routing operates upon.
  • 中介軟體可在 UseRouting 和之間執行, UseEndpoints 以便在執行端點之前處理路由的結果。Middleware can run between UseRouting and UseEndpoints to process the results of routing before the endpoint is executed.
    • 在和之間執行的中介軟體 UseRouting UseEndpointsMiddleware that runs between UseRouting and UseEndpoints:
      • 通常會檢查中繼資料以瞭解端點。Usually inspects metadata to understand the endpoints.
      • 通常會依照和完成安全性決策 UseAuthorization UseCorsOften makes security decisions, as done by UseAuthorization and UseCors.
    • 中介軟體和中繼資料的組合,可讓您設定每個端點的原則。The combination of middleware and metadata allows configuring policies per-endpoint.

上述程式碼顯示支援每個端點原則的自訂中介軟體範例。The preceding code shows an example of a custom middleware that supports per-endpoint policies. 中介軟體會將敏感性資料之存取權的審核記錄寫入主控台。The middleware writes an audit log of access to sensitive data to the console. 中介軟體可以設定為使用中繼資料來審核端點 AuditPolicyAttributeThe middleware can be configured to audit an endpoint with the AuditPolicyAttribute metadata. 這個範例會示範加入宣告模式,其中只會審核標示為機密的端點。This sample demonstrates an opt-in pattern where only endpoints that are marked as sensitive are audited. 例如,您可以反向定義此邏輯,以審核未標示為安全的所有專案。It's possible to define this logic in reverse, auditing everything that isn't marked as safe, for example. 端點中繼資料系統很有彈性。The endpoint metadata system is flexible. 這個邏輯可以設計成符合使用案例的任何方式。This logic could be designed in whatever way suits the use case.

先前的範例程式碼主要是用來示範端點的基本概念。The preceding sample code is intended to demonstrate the basic concepts of endpoints. 此範例並非供生產環境使用The sample is not intended for production use. 更完整的audit 記錄檔中介軟體版本如下:A more complete version of an audit log middleware would:

  • 記錄到檔案或資料庫。Log to a file or database.
  • 包含詳細資料,例如使用者、IP 位址、機密端點的名稱等等。Include details such as the user, IP address, name of the sensitive endpoint, and more.

稽核原則中繼資料 AuditPolicyAttribute 會定義為 Attribute ,以便更容易與以類別為基礎的架構(例如控制器和)搭配使用 SignalR 。The audit policy metadata AuditPolicyAttribute is defined as an Attribute for easier use with class-based frameworks such as controllers and SignalR. 使用路由至程式碼時:When using route to code:

  • 中繼資料是使用產生器 API 所附加。Metadata is attached with a builder API.
  • 以類別為基礎的架構在建立端點時,會在對應的方法和類別上包含所有屬性。Class-based frameworks include all attributes on the corresponding method and class when creating endpoints.

元資料類型的最佳作法是將它們定義為介面或屬性。The best practices for metadata types are to define them either as interfaces or attributes. 介面和屬性允許程式碼重複使用。Interfaces and attributes allow code reuse. 中繼資料系統具有彈性,而且不會強加任何限制。The metadata system is flexible and doesn't impose any limitations.

比較終端中介軟體和路由Comparing a terminal middleware and routing

下列程式碼範例會將中介軟體與使用路由進行對比:The following code sample contrasts using middleware with using routing:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    // Approach 1: Writing a terminal middleware.
    app.Use(next => async context =>
    {
        if (context.Request.Path == "/")
        {
            await context.Response.WriteAsync("Hello terminal middleware!");
            return;
        }

        await next(context);
    });

    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        // Approach 2: Using routing.
        endpoints.MapGet("/Movie", async context =>
        {
            await context.Response.WriteAsync("Hello routing!");
        });
    });
}

以顯示的中介軟體樣式 Approach 1:終端中介軟體The style of middleware shown with Approach 1: is terminal middleware. 這稱為「終端中介軟體」,因為它會執行比對作業:It's called terminal middleware because it does a matching operation:

  • 前述範例中的比對作業 Path == "/" 適用于中介軟體和 Path == "/Movie" 路由。The matching operation in the preceding sample is Path == "/" for the middleware and Path == "/Movie" for routing.
  • 當相符項成功時,它會執行一些功能並傳回,而不是叫用 next 中介軟體。When a match is successful, it executes some functionality and returns, rather than invoking the next middleware.

這稱為「終端中介軟體」,因為它會終止搜尋、執行一些功能,然後傳回。It's called terminal middleware because it terminates the search, executes some functionality, and then returns.

比較終端機中介軟體和路由:Comparing a terminal middleware and routing:

  • 這兩種方法都允許終止處理管線:Both approaches allow terminating the processing pipeline:
    • 中介軟體會藉由傳回而不是叫用來終止管線 nextMiddleware terminates the pipeline by returning rather than invoking next.
    • 端點一律是 [終端機]。Endpoints are always terminal.
  • 終端中介軟體允許將中介軟體放在管線中的任意位置:Terminal middleware allows positioning the middleware at an arbitrary place in the pipeline:
  • 終端中介軟體可讓任意程式碼判斷中介軟體何時符合:Terminal middleware allows arbitrary code to determine when the middleware matches:
    • 自訂路由比對程式碼可能很詳細,而且很容易正確寫入。Custom route matching code can be verbose and difficult to write correctly.
    • 路由為一般應用程式提供直接的解決方案。Routing provides straightforward solutions for typical apps. 大部分的應用程式都不需要自訂路由比對程式碼。Most apps don't require custom route matching code.
  • 具有中介軟體的端點介面,例如 UseAuthorizationUseCorsEndpoints interface with middleware such as UseAuthorization and UseCors.
    • 搭配或使用終端中介軟體時, UseAuthorization UseCors 必須手動與授權系統互動。Using a terminal middleware with UseAuthorization or UseCors requires manual interfacing with the authorization system.

端點會定義兩者:An endpoint defines both:

  • 用來處理要求的委派。A delegate to process requests.
  • 任意中繼資料的集合。A collection of arbitrary metadata. 中繼資料是用來根據附加至每個端點的原則和設定來執行跨領域考慮。The metadata is used to implement cross-cutting concerns based on policies and configuration attached to each endpoint.

終端中介軟體可以是有效的工具,但可能需要:Terminal middleware can be an effective tool, but can require:

  • 大量的編碼和測試。A significant amount of coding and testing.
  • 與其他系統進行手動整合,以達到所需的彈性層級。Manual integration with other systems to achieve the desired level of flexibility.

撰寫終端中介軟體之前,請考慮與路由整合。Consider integrating with routing before writing a terminal middleware.

Map或整合的現有終端機中介軟體, MapWhen 通常可以轉換成路由感知端點。Existing terminal middleware that integrates with Map or MapWhen can usually be turned into a routing aware endpoint. MapHealthChecks示範路由器的模式:MapHealthChecks demonstrates the pattern for router-ware:

下列程式碼示範如何使用MapHealthChecksThe following code shows use of MapHealthChecks:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    // Matches request to an endpoint.
    app.UseRouting();

    // Endpoint aware middleware. 
    // Middleware can use metadata from the matched endpoint.
    app.UseAuthentication();
    app.UseAuthorization();

    // Execute the matched endpoint.
    app.UseEndpoints(endpoints =>
    {
        // Configure the Health Check endpoint and require an authorized user.
        endpoints.MapHealthChecks("/healthz").RequireAuthorization();

        // Configure another endpoint, no authorization requirements.
        endpoints.MapGet("/", async context =>
        {
            await context.Response.WriteAsync("Hello World!");
        });
    });
}

上述範例顯示為何傳回產生器物件是很重要的。The preceding sample shows why returning the builder object is important. 傳回 builder 物件可讓應用程式開發人員設定原則,例如端點的授權。Returning the builder object allows the app developer to configure policies such as authorization for the endpoint. 在此範例中,健康狀態檢查中介軟體沒有與授權系統的直接整合。In this example, the health checks middleware has no direct integration with the authorization system.

已建立中繼資料系統,以回應擴充性作者使用終端機中介軟體所遇到的問題。The metadata system was created in response to the problems encountered by extensibility authors using terminal middleware. 每個中介軟體都有問題,使其與授權系統整合在一起。It's problematic for each middleware to implement its own integration with the authorization system.

URL 比對URL matching

  • 這是路由符合連入要求至端點的進程。Is the process by which routing matches an incoming request to an endpoint.
  • 是以 URL 路徑和標頭中的資料為基礎。Is based on data in the URL path and headers.
  • 可以擴充以考慮要求中的任何資料。Can be extended to consider any data in the request.

當路由中介軟體執行時,它會 Endpoint 從目前的要求將和路由值設定為上的要求功能 HttpContextWhen a routing middleware executes, it sets an Endpoint and route values to a request feature on the HttpContext from the current request:

在路由中介軟體之後執行的中介軟體可以檢查端點並採取動作。Middleware running after the routing middleware can inspect the endpoint and take action. 例如,授權中介軟體可以針對授權原則詢問端點的元資料集合。For example, an authorization middleware can interrogate the endpoint's metadata collection for an authorization policy. 執行要求處理管線中的所有中介軟體之後,會叫用所選端點的委派。After all of the middleware in the request processing pipeline is executed, the selected endpoint's delegate is invoked.

端點路由中的路由系統負責制定所有分派決策。The routing system in endpoint routing is responsible for all dispatching decisions. 因為中介軟體會根據選取的端點套用原則,所以請務必:Because the middleware applies policies based on the selected endpoint, it's important that:

  • 任何可能影響分派或應用安全性原則的決策都是在路由系統內進行。Any decision that can affect dispatching or the application of security policies is made inside the routing system.

警告

針對回溯相容性,當執行控制器或 Razor 頁面端點委派時,會根據到目前為止執行的要求處理,將routecoNtext.routedata的屬性設定為適當的值。For backwards-compatibility, when a Controller or Razor Pages endpoint delegate is executed, the properties of RouteContext.RouteData are set to appropriate values based on the request processing performed thus far.

RouteContext 未來的版本中,此類型將會標示為已淘汰:The RouteContext type will be marked obsolete in a future release:

  • 遷移 RouteData.ValuesHttpRequest.RouteValuesMigrate RouteData.Values to HttpRequest.RouteValues.
  • 遷移 RouteData.DataTokens 以從端點中繼資料取得IDataTokensMetadataMigrate RouteData.DataTokens to retrieve IDataTokensMetadata from the endpoint metadata.

URL 比對作業會以一組可設定的階段來運作。URL matching operates in a configurable set of phases. 在每個階段中,輸出是一組相符專案。In each phase, the output is a set of matches. 下一個階段可進一步縮小一組相符專案的範圍。The set of matches can be narrowed down further by the next phase. 路由執行並不保證符合端點的處理順序。The routing implementation does not guarantee a processing order for matching endpoints. 所有可能的相符專案都會一次處理。All possible matches are processed at once. URL 符合的階段會依照下列順序發生。The URL matching phases occur in the following order. ASP.NET Core:ASP.NET Core:

  1. 會處理一組端點及其路由範本的 URL 路徑,並收集所有相符專案。Processes the URL path against the set of endpoints and their route templates, collecting all of the matches.
  2. 接受上述清單,並移除已套用路由條件約束而失敗的相符專案。Takes the preceding list and removes matches that fail with route constraints applied.
  3. 接受上述清單並移除MatcherPolicy實例集失敗的相符專案。Takes the preceding list and removes matches that fail the set of MatcherPolicy instances.
  4. 會使用EndpointSelector ,從上述清單中進行最後的決策。Uses the EndpointSelector to make a final decision from the preceding list.

端點清單的優先順序會根據:The list of endpoints is prioritized according to:

所有相符的端點都會在每個階段中處理,直到 EndpointSelector 到達為止。All matching endpoints are processed in each phase until the EndpointSelector is reached. EndpointSelector是最後一個階段。The EndpointSelector is the final phase. 它會從相符專案中選擇最高優先順序的端點,以做為最符合專案。It chooses the highest priority endpoint from the matches as the best match. 如果有其他符合的優先權與最符合的專案相同,則會擲回不明確的相符例外狀況。If there are other matches with the same priority as the best match, an ambiguous match exception is thrown.

路由優先順序是根據指定較高優先順序的較特定路由範本來計算。The route precedence is computed based on a more specific route template being given a higher priority. 例如,請考慮範本 /hello/{message}For example, consider the templates /hello and /{message}:

  • 兩者都符合 URL 路徑 /helloBoth match the URL path /hello.
  • /hello更明確,因此優先順序較高。/hello is more specific and therefore higher priority.

一般來說,路由優先順序會針對實務中使用的 URL 配置類型選擇最符合的工作。In general, route precedence does a good job of choosing the best match for the kinds of URL schemes used in practice. Order只有在必要時才使用,以避免發生不明確的情況。Use Order only when necessary to avoid an ambiguity.

由於路由所提供的擴充性種類,路由系統無法在不明確的路由時間之前計算。Due to the kinds of extensibility provided by routing, it isn't possible for the routing system to compute ahead of time the ambiguous routes. 假設有一個範例,例如路由範本 /{message:alpha}/{message:int}Consider an example such as the route templates /{message:alpha} and /{message:int}:

  • alpha條件約束只符合字母字元。The alpha constraint matches only alphabetic characters.
  • int條件約束只符合數位。The int constraint matches only numbers.
  • 這些範本具有相同的路由優先順序,但沒有相符的單一 URL。These templates have the same route precedence, but there's no single URL they both match.
  • 如果路由系統在啟動時報告了不明確的錯誤,則會封鎖此有效的使用案例。If the routing system reported an ambiguity error at startup, it would block this valid use case.

警告

內部作業的順序 UseEndpoints 不會影響路由的行為,但有一個例外狀況。The order of operations inside UseEndpoints doesn't influence the behavior of routing, with one exception. MapControllerRoute和會根據叫用 MapAreaRoute 的順序,自動指派訂單值給其端點。MapControllerRoute and MapAreaRoute automatically assign an order value to their endpoints based on the order they are invoked. 這會模擬控制器的長時間行為,而不會有路由系統提供與舊版路由執行相同的保證。This simulates long-time behavior of controllers without the routing system providing the same guarantees as older routing implementations.

在路由的舊版執行中,可以根據路由的處理順序來執行路由擴充性。In the legacy implementation of routing, it's possible to implement routing extensibility that has a dependency on the order in which routes are processed. ASP.NET Core 3.0 和更新版本中的端點路由:Endpoint routing in ASP.NET Core 3.0 and later:

  • 沒有路由的概念。Doesn't have a concept of routes.
  • 不提供排序保證。Doesn't provide ordering guarantees. 所有端點都會一次處理。All endpoints are processed at once.

如果這表示您在使用舊版路由系統時停滯,請開啟 GitHub 問題以取得協助If this means you're stuck using the legacy routing system, open a GitHub issue for assistance.

路由範本優先順序和端點選取順序Route template precedence and endpoint selection order

路由範本優先順序是一種系統,它會根據特定的方式,為每個路由範本指派一個值。Route template precedence is a system that assigns each route template a value based on how specific it is. 路由範本優先順序:Route template precedence:

  • 避免在一般情況下調整端點順序的需求。Avoids the need to adjust the order of endpoints in common cases.
  • 嘗試符合常見的路由行為預期。Attempts to match the common-sense expectations of routing behavior.

例如,請考慮範本 /Products/List/Products/{id}For example, consider templates /Products/List and /Products/{id}. 假設 /Products/List 比起 URL 路徑的比對更相符,這是合理的做法 /Products/{id} /Products/ListIt would be reasonable to assume that /Products/List is a better match than /Products/{id} for the URL path /Products/List. 的作用是因為常 /List 值區段被視為具有比參數區段更好的優先順序 /{id}The works because the literal segment /List is considered to have better precedence than the parameter segment /{id}.

優先順序運作方式的詳細資料會結合如何定義路由範本:The details of how precedence works are coupled to how route templates are defined:

  • 具有更多區段的範本會被視為更明確。Templates with more segments are considered more specific.
  • 具有常值文字的區段會被視為比參數區段更明確。A segment with literal text is considered more specific than a parameter segment.
  • 具有條件約束的參數區段在沒有的情況下會被視為較明確。A parameter segment with a constraint is considered more specific than one without.
  • 複雜的區段會被視為具有條件約束的參數區段。A complex segment is considered as specific as a parameter segment with a constraint.
  • Catch-all 參數是最不明確的。Catch-all parameters are the least specific. 如需有關 catch all 路由的重要資訊,請參閱路由範本參考中的全部攔截See catch-all in the Route template reference for important information on catch-all routes.

如需確切值的參考,請參閱GitHub 上的原始程式碼See the source code on GitHub for a reference of exact values.

URL 產生概念URL generation concepts

URL 產生:URL generation:

  • 這是路由可以根據一組路由值建立 URL 路徑的進程。Is the process by which routing can create a URL path based on a set of route values.
  • 允許端點與存取它們的 Url 之間的邏輯分隔。Allows for a logical separation between endpoints and the URLs that access them.

端點路由包含 LinkGenerator API。Endpoint routing includes the LinkGenerator API. LinkGeneratorDI提供的單一服務。LinkGenerator is a singleton service available from DI. LinkGeneratorAPI 可以在執行中要求的內容之外使用。The LinkGenerator API can be used outside of the context of an executing request. IUrlHelper和依賴的案例,例如標籤協助程式 IUrlHelper 、HTML 協助程式和動作結果,會在Tag Helpers內部使用 LinkGenerator API 來提供連結產生功能。Mvc.IUrlHelper and scenarios that rely on IUrlHelper, such as Tag Helpers, HTML Helpers, and Action Results, use the LinkGenerator API internally to provide link generating capabilities.

連結產生器背後支援的概念為「位址」**** 和「位址配置」****。The link generator is backed by the concept of an address and address schemes. 位址配置可讓您判斷應考慮用於連結產生的端點。An address scheme is a way of determining the endpoints that should be considered for link generation. 例如,許多使用者熟悉的路由名稱和路由值案例會將控制器和頁面實 Razor 作為位址配置。For example, the route name and route values scenarios many users are familiar with from controllers and Razor Pages are implemented as an address scheme.

連結產生器可以透過下列擴充方法連結至控制器和 Razor 頁面:The link generator can link to controllers and Razor Pages via the following extension methods:

這些方法的多載會接受包含的引數 HttpContextOverloads of these methods accept arguments that include the HttpContext. 這些方法在功能上相當於url. 動作url,但提供額外的彈性和選項。These methods are functionally equivalent to Url.Action and Url.Page, but offer additional flexibility and options.

這些 GetPath* 方法與和最相似 Url.Action Url.Page ,因為它們會產生包含絕對路徑的 URI。The GetPath* methods are most similar to Url.Action and Url.Page, in that they generate a URI containing an absolute path. GetUri* 方法一律會產生包含配置和主機的絕對 URI。The GetUri* methods always generate an absolute URI containing a scheme and host. 接受 HttpContext 的方法會在執行要求的內容中產生 URI。The methods that accept an HttpContext generate a URI in the context of the executing request. 除非覆寫,否則會使用執行中要求的環境路由值、URL 基底路徑、配置和主機。The ambient route values, URL base path, scheme, and host from the executing request are used unless overridden.

呼叫 LinkGenerator 並指定一個位址。LinkGenerator is called with an address. 執行下列兩個步驟來產生 URI:Generating a URI occurs in two steps:

  1. 將位址繫結至符合該位址的端點清單。An address is bound to a list of endpoints that match the address.
  2. 評估每個端點的 RoutePattern,直到找到符合所提供值的路由模式。Each endpoint's RoutePattern is evaluated until a route pattern that matches the supplied values is found. 產生的輸出會與提供給連結產生器的其他 URI 組件合併並傳回。The resulting output is combined with the other URI parts supplied to the link generator and returned.

LinkGenerator 提供的方法支援適用於任何位址類型的標準連結產生功能。The methods provided by LinkGenerator support standard link generation capabilities for any type of address. 使用連結產生器最方便的方式,就是透過擴充方法來執行特定網址類別型的作業:The most convenient way to use the link generator is through extension methods that perform operations for a specific address type:

擴充方法Extension Method 描述Description
GetPathByAddress 根據提供的值產生具有絕對路徑的 URI。Generates a URI with an absolute path based on the provided values.
GetUriByAddress 根據提供的值產生絕對 URI。Generates an absolute URI based on the provided values.

警告

注意呼叫 LinkGenerator 方法的下列影響:Pay attention to the following implications of calling LinkGenerator methods:

  • 使用 GetUri* 擴充方法,並注意應用程式組態不會驗證傳入要求的 Host 標頭。Use GetUri* extension methods with caution in an app configuration that doesn't validate the Host header of incoming requests. 如果 Host 未驗證傳入要求的標頭,則不受信任的要求輸入可以在視圖或頁面的 uri 中傳回給用戶端。If the Host header of incoming requests isn't validated, untrusted request input can be sent back to the client in URIs in a view or page. 建議所有生產應用程式將其伺服器設定為驗證 Host 標頭是否為已知有效值。We recommend that all production apps configure their server to validate the Host header against known valid values.

  • 使用 LinkGenerator,並注意與 MapMapWhen 搭配使用的中介軟體。Use LinkGenerator with caution in middleware in combination with Map or MapWhen. Map* 會變更執行要求的基底路徑,這會影響連結產生的輸出。Map* changes the base path of the executing request, which affects the output of link generation. 所有的 LinkGenerator API 都允許指定基底路徑。All of the LinkGenerator APIs allow specifying a base path. 指定空的基底路徑,以復原 Map* 連結產生的影響。Specify an empty base path to undo the Map* affect on link generation.

中介軟體範例Middleware example

在下列範例中,中介軟體會使用 LinkGenerator API 來建立列出商店產品之動作方法的連結。In the following example, a middleware uses the LinkGenerator API to create a link to an action method that lists store products. 藉由將連結產生器插入類別並呼叫, GenerateLink 可供應用程式中的任何類別使用:Using the link generator by injecting it into a class and calling GenerateLink is available to any class in an app:

public class ProductsLinkMiddleware
{
    private readonly LinkGenerator _linkGenerator;

    public ProductsLinkMiddleware(RequestDelegate next, LinkGenerator linkGenerator)
    {
        _linkGenerator = linkGenerator;
    }

    public async Task InvokeAsync(HttpContext httpContext)
    {
        var url = _linkGenerator.GetPathByAction("ListProducts", "Store");

        httpContext.Response.ContentType = "text/plain";

        await httpContext.Response.WriteAsync($"Go to {url} to see our products.");
    }
}

路由範本參考Route template reference

{} 的 token 會定義路由符合時所系結的路由參數。Tokens within {} define route parameters that are bound if the route is matched. 在路由區段中可以定義一個以上的路由參數,但路由參數必須以常值分隔。More than one route parameter can be defined in a route segment, but route parameters must be separated by a literal value. 例如,{controller=Home}{action=Index} 不是有效的路由,因為 {controller}{action} 之間沒有任何常值。For example, {controller=Home}{action=Index} isn't a valid route, since there's no literal value between {controller} and {action}. 路由參數必須有名稱,而且可能會指定其他屬性。Route parameters must have a name and may have additional attributes specified.

路由參數之外的常值文字 (例如,{id}) 和路徑分隔符號 / 必須符合 URL 中的文字。Literal text other than route parameters (for example, {id}) and the path separator / must match the text in the URL. 文字比對不區分大小寫,而且會根據 URL 路徑的解碼標記法。Text matching is case-insensitive and based on the decoded representation of the URL's path. 若要比對常值路由參數分隔符號 {} ,請重複字元來將分隔符號轉義。To match a literal route parameter delimiter { or }, escape the delimiter by repeating the character. 例如, {{}}For example {{ or }}.

星號 * 或雙星號 **Asterisk * or double asterisk **:

  • 可以做為路由參數的前置詞,以系結至 URI 的其餘部分。Can be used as a prefix to a route parameter to bind to the rest of the URI.
  • 稱為「全部攔截」參數。Are called a catch-all parameters. 例如,blog/{**slug}For example, blog/{**slug}:
    • 會比對開頭為的任何 URI /blog ,並在其後面加上任何值。Matches any URI that starts with /blog and has any value following it.
    • 下列值 /blog 會指派給 [資訊區路線] 路由值。The value following /blog is assigned to the slug route value.

警告

Catch-all參數可能會因為路由中的錯誤而不正確地符合路由。A catch-all parameter may match routes incorrectly due to a bug in routing. 受此錯誤影響的應用程式具有下列特性:Apps impacted by this bug have the following characteristics:

  • 全部捕捉路由,例如{**slug}"A catch-all route, for example, {**slug}"
  • Catch-all 路由無法符合它應該符合的要求。The catch-all route fails to match requests it should match.
  • 移除其他路由會使「全部攔截」路由開始運作。Removing other routes makes catch-all route start working.

如需遇到此 bug 的範例案例,請參閱 GitHub bug 1867716579See GitHub bugs 18677 and 16579 for example cases that hit this bug.

.Net Core 3.1.301 SDK 和更新版本中包含這個 bug 的加入宣告修正程式。An opt-in fix for this bug is contained in .NET Core 3.1.301 SDK and later. 下列程式碼會設定可修正此 bug 的內部交換器:The following code sets an internal switch that fixes this bug:

public static void Main(string[] args)
{
   AppContext.SetSwitch("Microsoft.AspNetCore.Routing.UseCorrectCatchAllBehavior", 
                         true);
   CreateHostBuilder(args).Build().Run();
}
// Remaining code removed for brevity.

全部擷取參數也可以符合空字串。Catch-all parameters can also match the empty string.

當使用路由來產生 URL (包括路徑分隔符號)時,catch-all 參數會將適當的字元進行轉義 /The catch-all parameter escapes the appropriate characters when the route is used to generate a URL, including path separator / characters. 例如,路由值為 { path = "my/path" } 的路由 foo/{*path} 會產生 foo/my%2FpathFor example, the route foo/{*path} with route values { path = "my/path" } generates foo/my%2Fpath. 請注意逸出的斜線。Note the escaped forward slash. 若要反覆存取路徑分隔符號字元,請使用 ** 路由參數前置詞。To round-trip path separator characters, use the ** route parameter prefix. 具有 { path = "my/path" } 的路由 foo/{**path} 會產生 foo/my/pathThe route foo/{**path} with { path = "my/path" } generates foo/my/path.

URL 模式嘗試擷取具有選擇性副檔名的檔案名稱時,具有其他考量。URL patterns that attempt to capture a file name with an optional file extension have additional considerations. 以範本 files/{filename}.{ext?} 為例。For example, consider the template files/{filename}.{ext?}. filenameext 都存在值時,就會填入這兩個值。When values for both filename and ext exist, both values are populated. 如果 filename URL 中只有存在的值,則路由會符合,因為尾端 . 是選擇性的。If only a value for filename exists in the URL, the route matches because the trailing . is optional. 下列 URL 符合此路由:The following URLs match this route:

  • /files/myFile.txt
  • /files/myFile

路由參數可能有「預設值」****,指定方法是在參數名稱之後指定預設值,並以等號 (=) 分隔。Route parameters may have default values designated by specifying the default value after the parameter name separated by an equals sign (=). 例如,{controller=Home} 定義 Home 作為 controller 的預設值。For example, {controller=Home} defines Home as the default value for controller. 如果 URL 中沒有用於參數的任何值,則會使用預設值。The default value is used if no value is present in the URL for the parameter. 藉由將問號 (?) 附加至參數名稱的結尾,即可將路由參數設為選擇性。Route parameters are made optional by appending a question mark (?) to the end of the parameter name. 例如,id?For example, id?. 選擇性值與預設路由參數之間的差異如下:The difference between optional values and default route parameters is:

  • 具有預設值的路由參數一律會產生值。A route parameter with a default value always produces a value.
  • 選擇性參數只有在要求 URL 提供值時才會有值。An optional parameter has a value only when a value is provided by the request URL.

路由參數可能具有條件約束,這些條件約束必須符合與 URL 繫結的路由值。Route parameters may have constraints that must match the route value bound from the URL. : 路由參數名稱之後加入和條件約束名稱,會在路由參數上指定內嵌條件約束。Adding : and constraint name after the route parameter name specifies an inline constraint on a route parameter. 如果條件約束需要引數,這些引數會在條件約束名稱後面以括弧 (...) 括住。If the constraint requires arguments, they're enclosed in parentheses (...) after the constraint name. 藉由附加另一個和條件約束名稱,可以指定多個內嵌條件約束 :Multiple inline constraints can be specified by appending another : and constraint name.

條件約束名稱和引述會傳遞至 IInlineConstraintResolver 服務來建立 IRouteConstraint 的執行個體,以用於 URL 處理。The constraint name and arguments are passed to the IInlineConstraintResolver service to create an instance of IRouteConstraint to use in URL processing. 例如,路由範本 blog/{article:minlength(10)} 指定具有引數 10minlength 條件約束。For example, the route template blog/{article:minlength(10)} specifies a minlength constraint with the argument 10. 如需路由條件約束詳細資訊和架構所提供的條件約束清單,請參閱路由條件約束參考一節。For more information on route constraints and a list of the constraints provided by the framework, see the Route constraint reference section.

路由參數也可以具有參數轉換器。Route parameters may also have parameter transformers. 參數轉換器會在產生連結並比對動作和頁面到 Url 時,轉換參數的值。Parameter transformers transform a parameter's value when generating links and matching actions and pages to URLs. 如同條件約束,參數轉換器可以藉由 : 在路由參數名稱之後新增和轉換器名稱,以內嵌方式加入至路由參數。Like constraints, parameter transformers can be added inline to a route parameter by adding a : and transformer name after the route parameter name. 例如,路由範本 blog/{article:slugify} 會指定 slugify 轉換器。For example, the route template blog/{article:slugify} specifies a slugify transformer. 如需參數轉換器的詳細資訊,請參閱參數轉器參考一節。For more information on parameter transformers, see the Parameter transformer reference section.

下表示范範例路由範本及其行為:The following table demonstrates example route templates and their behavior:

路由範本Route Template 範例比對 URIExample Matching URI 要求 URI…The request URI…
hello /hello 只比對單一路徑 /helloOnly matches the single path /hello.
{Page=Home} / 比對並將 Page 設定為 HomeMatches and sets Page to Home.
{Page=Home} /Contact 比對並將 Page 設定為 ContactMatches and sets Page to Contact.
{controller}/{action}/{id?} /Products/List 對應至 Products 控制器和 List 動作。Maps to the Products controller and List action.
{controller}/{action}/{id?} /Products/Details/123 對應至 Products 控制器和 Details 動作,並 id 將設定為123。Maps to the Products controller and Details action withid set to 123.
{controller=Home}/{action=Index}/{id?} / 對應至 Home 控制器和 Index 方法。Maps to the Home controller and Index method. id 會被忽略。id is ignored.
{controller=Home}/{action=Index}/{id?} /Products 對應至 Products 控制器和 Index 方法。Maps to the Products controller and Index method. id 會被忽略。id is ignored.

使用範本通常是最簡單的路由方式。Using a template is generally the simplest approach to routing. 條件約束和預設值也可以在路由範本外部指定。Constraints and defaults can also be specified outside the route template.

複雜區段Complex segments

複雜區段的處理方式是以非貪婪的方式,將常值分隔符號從右至左比對。Complex segments are processed by matching up literal delimiters from right to left in a non-greedy way. 例如, [Route("/a{b}c{d}")] 是一個複雜的區段。For example, [Route("/a{b}c{d}")] is a complex segment. 複雜的區段會以特定的方式工作,必須瞭解才能成功使用它們。Complex segments work in a particular way that must be understood to use them successfully. 本章節中的範例將示範當分隔符號文字不會出現在參數值內時,複雜區段的效果為何。The example in this section demonstrates why complex segments only really work well when the delimiter text doesn't appear inside the parameter values. 在較複雜的情況下,需要使用RegEx ,然後手動將值解壓縮。Using a regex and then manually extracting the values is needed for more complex cases.

警告

當使用System.Text.RegularExpressions來處理不受信任的輸入時,請傳遞超時。When using System.Text.RegularExpressions to process untrusted input, pass a timeout. 惡意使用者可以提供輸入, RegularExpressions導致拒絕服務攻擊A malicious user can provide input to RegularExpressions causing a Denial-of-Service attack. 使用RegularExpressions的 ASP.NET Core framework api 會傳遞超時。ASP.NET Core framework APIs that use RegularExpressions pass a timeout.

這是路由執行的步驟 /a{b}c{d} 和範本和 URL 路徑的摘要 /abcdThis is a summary of the steps that routing performs with the template /a{b}c{d} and the URL path /abcd. |是用來協助視覺化演算法的運作方式:The | is used to help visualize how the algorithm works:

  • 第一個常值(由右至左)為 cThe first literal, right to left, is c. 因此, /abcd 會向右搜尋並尋找 /ab|c|dSo /abcd is searched from right and finds /ab|c|d.
  • 右 () 的所有內容 d 現在都符合路由參數 {d}Everything to the right (d) is now matched to the route parameter {d}.
  • 下一個常值(由右至左)為 aThe next literal, right to left, is a. 因此, /ab|c|d 在從離開的地方開始搜尋,然後 a 找到 /|a|b|c|dSo /ab|c|d is searched starting where we left off, then a is found /|a|b|c|d.
  • 右邊 (的值 b) 現在會符合路由參數 {b}The value to the right (b) is now matched to the route parameter {b}.
  • 沒有任何剩餘的文字,也沒有剩餘的路由範本,因此這是相符的。There is no remaining text and no remaining route template, so this is a match.

以下是使用相同範本和 URL 路徑的負面案例範例 /a{b}c{d} /aabcdHere's an example of a negative case using the same template /a{b}c{d} and the URL path /aabcd. |是用來協助視覺化演算法的運作方式。The | is used to help visualize how the algorithm works. 這種情況並不相符,這會透過相同的演算法來說明:This case isn't a match, which is explained by the same algorithm:

  • 第一個常值(由右至左)為 cThe first literal, right to left, is c. 因此, /aabcd 會向右搜尋並尋找 /aab|c|dSo /aabcd is searched from right and finds /aab|c|d.
  • 右 () 的所有內容 d 現在都符合路由參數 {d}Everything to the right (d) is now matched to the route parameter {d}.
  • 下一個常值(由右至左)為 aThe next literal, right to left, is a. 因此, /aab|c|d 在從離開的地方開始搜尋,然後 a 找到 /a|a|b|c|dSo /aab|c|d is searched starting where we left off, then a is found /a|a|b|c|d.
  • 右邊 (的值 b) 現在會符合路由參數 {b}The value to the right (b) is now matched to the route parameter {b}.
  • 此時會有剩餘的文字 a ,但演算法已用完路由範本進行剖析,因此這不是相符的。At this point there is remaining text a, but the algorithm has run out of route template to parse, so this is not a match.

因為比對演算法是非貪婪的:Since the matching algorithm is non-greedy:

  • 它會比對每個步驟中可能的最小文字數量。It matches the smallest amount of text possible in each step.
  • 在參數值內出現分隔符號值的任何情況下,都會導致不相符。Any case where the delimiter value appears inside the parameter values results in not matching.

正則運算式可讓您更充分掌控其比對行為。Regular expressions provide much more control over their matching behavior.

貪婪比對(也稱為延遲比對)符合最大的可能字串。Greedy matching, also know as lazy matching, matches the largest possible string. 非貪婪的會符合最小的可能字串。Non-greedy matches the smallest possible string.

路由條件約束參考Route constraint reference

路由條件約束執行時機是出現符合傳入 URL 的項目,並將 URL 路徑語彙基元化成路由值時。Route constraints execute when a match has occurred to the incoming URL and the URL path is tokenized into route values. 路由條件約束通常會檢查透過路由範本相關聯的路由值,並對值是否可接受進行 true 或 false 的決策。Route constraints generally inspect the route value associated via the route template and make a true or false decision about whether the value is acceptable. 某些路由條件約束會使用路由值以外的資料,以考慮是否可以路由要求。Some route constraints use data outside the route value to consider whether the request can be routed. 例如,HttpMethodRouteConstraint 可以依據其 HTTP 指令動詞接受或拒絕要求。For example, the HttpMethodRouteConstraint can accept or reject a request based on its HTTP verb. 條件約束可用於路由要求和連結產生。Constraints are used in routing requests and link generation.

警告

請勿針對輸入驗證使用條件約束。Don't use constraints for input validation. 如果條件約束用於輸入驗證,則不正確輸入會導致找不到的 404 回應。If constraints are used for input validation, invalid input results in a 404 Not Found response. 不正確輸入應該會產生不 400 正確的要求,並出現適當的錯誤訊息。Invalid input should produce a 400 Bad Request with an appropriate error message. 路由條件約束會用來釐清類似的路由,而不是用來驗證特定路由的輸入。Route constraints are used to disambiguate similar routes, not to validate the inputs for a particular route.

下表示范範例路由條件約束及其預期行為:The following table demonstrates example route constraints and their expected behavior:

constraint (條件約束)constraint 範例Example 範例相符項目Example Matches 附註Notes
int {id:int} 123456789, -123456789123456789, -123456789 符合任何整數Matches any integer
bool {active:bool} true, FALSEtrue, FALSE 符合 truefalseMatches true or false. 不區分大小寫Case-insensitive
datetime {dob:datetime} 2016-12-31, 2016-12-31 7:32pm2016-12-31, 2016-12-31 7:32pm 符合不因文化特性而異的有效 DateTime 值。Matches a valid DateTime value in the invariant culture. 請參閱先前的警告。See preceding warning.
decimal {price:decimal} 49.99, -1,000.0149.99, -1,000.01 符合不因文化特性而異的有效 decimal 值。Matches a valid decimal value in the invariant culture. 請參閱先前的警告。See preceding warning.
double {weight:double} 1.234, -1,001.01e81.234, -1,001.01e8 符合不因文化特性而異的有效 double 值。Matches a valid double value in the invariant culture. 請參閱先前的警告。See preceding warning.
float {weight:float} 1.234, -1,001.01e81.234, -1,001.01e8 符合不因文化特性而異的有效 float 值。Matches a valid float value in the invariant culture. 請參閱先前的警告。See preceding warning.
guid {id:guid} CD2C1638-1638-72D5-1638-DEADBEEF1638 符合有效的 GuidMatches a valid Guid value
long {ticks:long} 123456789, -123456789123456789, -123456789 符合有效的 longMatches a valid long value
minlength(value) {username:minlength(4)} Rick 字串必須至少有 4 個字元String must be at least 4 characters
maxlength(value) {filename:maxlength(8)} MyFile 字串不能超過 8 個字元String must be no more than 8 characters
length(length) {filename:length(12)} somefile.txt 字串長度必須剛好是 12 個字元String must be exactly 12 characters long
length(min,max) {filename:length(8,16)} somefile.txt 字串長度必須至少有 8 個字元,但不能超過 16 個字元String must be at least 8 and no more than 16 characters long
min(value) {age:min(18)} 19 整數值必須至少為 18Integer value must be at least 18
max(value) {age:max(120)} 91 整數值不能超過 120Integer value must be no more than 120
range(min,max) {age:range(18,120)} 91 整數值必須至少為 18,但不能超過 120Integer value must be at least 18 but no more than 120
alpha {name:alpha} Rick 字串必須包含一或多個字母字元, a - z 並不區分大小寫。String must consist of one or more alphabetical characters, a-z and case-insensitive.
regex(expression) {ssn:regex(^\\d{{3}}-\\d{{2}}-\\d{{4}}$)} 123-45-6789 字串必須符合正則運算式。String must match the regular expression. 請參閱定義正則運算式的秘訣。See tips about defining a regular expression.
required {name:required} Rick 用來強制執行在 URL 產生期間呈現非參數值Used to enforce that a non-parameter value is present during URL generation

警告

當使用System.Text.RegularExpressions來處理不受信任的輸入時,請傳遞超時。When using System.Text.RegularExpressions to process untrusted input, pass a timeout. 惡意使用者可以提供輸入, RegularExpressions導致拒絕服務攻擊A malicious user can provide input to RegularExpressions causing a Denial-of-Service attack. 使用RegularExpressions的 ASP.NET Core framework api 會傳遞超時。ASP.NET Core framework APIs that use RegularExpressions pass a timeout.

多個以冒號分隔的條件約束可以套用至單一參數。Multiple, colon delimited constraints can be applied to a single parameter. 例如,下列條件約束會將參數限制在 1 或更大的整數值:For example, the following constraint restricts a parameter to an integer value of 1 or greater:

[Route("users/{id:int:min(1)}")]
public User GetUserById(int id) { }

警告

驗證 URL 並轉換成 CLR 類型的路由條件約束,一律會使用不因文化特性而異。Route constraints that verify the URL and are converted to a CLR type always use the invariant culture. 例如,轉換成 CLR 型別 intDateTimeFor example, conversion to the CLR type int or DateTime. 這些條件約束假設 URL 無法當地語系化。These constraints assume that the URL is not localizable. 架構提供的路由條件約束不會修改路由值中儲存的值。The framework-provided route constraints don't modify the values stored in route values. 所有從 URL 剖析而來的路由值會儲存為字串。All route values parsed from the URL are stored as strings. 例如,float 條件約束會嘗試將路由值轉換成浮點數,但轉換的值只能用來確認它可以轉換成浮點數。For example, the float constraint attempts to convert the route value to a float, but the converted value is used only to verify it can be converted to a float.

條件約束中的正則運算式Regular expressions in constraints

警告

當使用System.Text.RegularExpressions來處理不受信任的輸入時,請傳遞超時。When using System.Text.RegularExpressions to process untrusted input, pass a timeout. 惡意使用者可以提供輸入, RegularExpressions導致拒絕服務攻擊A malicious user can provide input to RegularExpressions causing a Denial-of-Service attack. 使用RegularExpressions的 ASP.NET Core framework api 會傳遞超時。ASP.NET Core framework APIs that use RegularExpressions pass a timeout.

正則運算式可以指定為使用路由條件約束的內嵌條件約束 regex(...)Regular expressions can be specified as inline constraints using the regex(...) route constraint. 系列中的方法 MapControllerRoute 也會接受條件約束的物件常值。Methods in the MapControllerRoute family also accept an object literal of constraints. 如果使用該表單,字串值就會被視為正則運算式。If that form is used, string values are interpreted as regular expressions.

下列程式碼會使用內嵌 RegEx 條件約束:The following code uses an inline regex constraint:

app.UseEndpoints(endpoints =>
{
    endpoints.MapGet("{message:regex(^\\d{{3}}-\\d{{2}}-\\d{{4}}$)}",
        context => 
        {
            return context.Response.WriteAsync("inline-constraint match");
        });
 });

下列程式碼會使用物件常值來指定 RegEx 條件約束:The following code uses an object literal to specify a regex constraint:

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(
        name: "people",
        pattern: "People/{ssn}",
        constraints: new { controller = "^\\d{3}-\\d{2}-\\d{4}$", },
        defaults: new { controller = "People", action = "List", });
});

ASP.NET Core 架構將 RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvariant 新增至規則運算式建構函式。The ASP.NET Core framework adds RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvariant to the regular expression constructor. 如需這些成員的說明,請參閱 RegexOptionsSee RegexOptions for a description of these members.

正則運算式會使用類似路由和 c # 語言所使用的分隔符號和標記。Regular expressions use delimiters and tokens similar to those used by routing and the C# language. 規則運算式的語彙基元必須逸出。Regular expression tokens must be escaped. 若要 ^\d{3}-\d{2}-\d{4}$ 在內嵌條件約束中使用正則運算式,請使用下列其中一項:To use the regular expression ^\d{3}-\d{2}-\d{4}$ in an inline constraint, use one of the following:

  • \ 字串中提供的字元取代為 c # 原始檔中的字元,以便 \\\ 字串 escape 字元轉義。Replace \ characters provided in the string as \\ characters in the C# source file in order to escape the \ string escape character.
  • 逐字字串常值。Verbatim string literals.

若要轉義路由參數分隔符號 {}[ 、,請將 ] 運算式中的字元加倍,例如、 {{}} [[]]To escape routing parameter delimiter characters {, }, [, ], double the characters in the expression, for example, {{, }}, [[, ]]. 下表顯示正則運算式和其轉義版本:The following table shows a regular expression and its escaped version:

規則運算式Regular expression 已轉義的正則運算式Escaped regular expression
^\d{3}-\d{2}-\d{4}$ ^\\d{{3}}-\\d{{2}}-\\d{{4}}$
^[a-z]{2}$ ^[[a-z]]{{2}}$

路由中使用的正則運算式通常以 ^ 字元開頭,並符合字串的開始位置。Regular expressions used in routing often start with the ^ character and match the starting position of the string. 運算式通常以 $ 字元結尾,並符合字串的結尾。The expressions often end with the $ character and match the end of the string. ^$ 字元可確保正則運算式符合整個路由參數值。The ^ and $ characters ensure that the regular expression matches the entire route parameter value. 如果沒有 ^$ 字元,正則運算式會比對字串內的任何子字串,這通常是不需要的。Without the ^ and $ characters, the regular expression matches any substring within the string, which is often undesirable. 下表提供範例,並說明它們符合或無法符合的原因:The following table provides examples and explains why they match or fail to match:

運算式Expression StringString 比對Match 註解Comment
[a-z]{2} hellohello Yes 子字串相符項目Substring matches
[a-z]{2} 123abc456123abc456 Yes 子字串相符項目Substring matches
[a-z]{2} mzmz Yes 符合運算式Matches expression
[a-z]{2} MZMZ Yes 不區分大小寫Not case sensitive
^[a-z]{2}$ hellohello No 請參閱上述的 ^$See ^ and $ above
^[a-z]{2}$ 123abc456123abc456 No 請參閱上述的 ^$See ^ and $ above

如需規則運算式語法的詳細資訊,請參閱 .NET Framework 規則運算式For more information on regular expression syntax, see .NET Framework Regular Expressions.

若要將參數限制為一組已知的可能值,請使用規則運算式。To constrain a parameter to a known set of possible values, use a regular expression. 例如,{action:regex(^(list|get|create)$)} 只會將 action 路由值與 listgetcreate 相符。For example, {action:regex(^(list|get|create)$)} only matches the action route value to list, get, or create. 如果已傳入條件約束字典,字串 ^(list|get|create)$ 則是對等項目。If passed into the constraints dictionary, the string ^(list|get|create)$ is equivalent. 在條件約束字典中傳遞並不符合其中一個已知條件約束的條件約束,也會被視為正則運算式。Constraints that are passed in the constraints dictionary that don't match one of the known constraints are also treated as regular expressions. 在不符合其中一個已知條件約束的範本內傳遞的條件約束,不會被視為正則運算式。Constraints that are passed within a template that don't match one of the known constraints are not treated as regular expressions.

自訂路由條件約束Custom route constraints

您可以藉由執行介面來建立自訂路由條件約束 IRouteConstraintCustom route constraints can be created by implementing the IRouteConstraint interface. IRouteConstraint介面包含 Matchtrue 如果條件約束已滿足,則會傳回,否則會傳回 falseThe IRouteConstraint interface contains Match, which returns true if the constraint is satisfied and false otherwise.

很少需要自訂路由條件約束。Custom route constraints are rarely needed. 在執行自訂路由條件約束之前,請考慮使用替代專案,例如模型系結。Before implementing a custom route constraint, consider alternatives, such as model binding.

[ASP.NET Core條件約束] 資料夾會提供建立條件約束的良好範例。The ASP.NET Core Constraints folder provides good examples of creating a constraints. 例如, GuidRouteConstraintFor example, GuidRouteConstraint.

若要使用自訂 IRouteConstraint ,則必須向 ConstraintMap 服務容器中的應用程式註冊路由條件約束類型。To use a custom IRouteConstraint, the route constraint type must be registered with the app's ConstraintMap in the service container. ConstraintMap 是一個目錄,它將路由限制式機碼對應到可驗證那些限制式的 IRouteConstraint 實作。A ConstraintMap is a dictionary that maps route constraint keys to IRouteConstraint implementations that validate those constraints. 更新應用程式的 ConstraintMap 時,可在 Startup.ConfigureServices 中於進行 services.AddRouting 呼叫時更新,或透過使用 services.Configure<RouteOptions> 直接設定 RouteOptions 來更新。An app's ConstraintMap can be updated in Startup.ConfigureServices either as part of a services.AddRouting call or by configuring RouteOptions directly with services.Configure<RouteOptions>. 例如:For example:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();

    services.AddRouting(options =>
    {
        options.ConstraintMap.Add("customName", typeof(MyCustomConstraint));
    });
}

上述條件約束會套用至下列程式碼:The preceding constraint is applied in the following code:

[Route("api/[controller]")]
[ApiController]
public class TestController : ControllerBase
{
    // GET /api/test/3
    [HttpGet("{id:customName}")]
    public IActionResult Get(string id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }

    // GET /api/test/my/3
    [HttpGet("my/{id:customName}")]
    public IActionResult Get(int id)
    {
        return ControllerContext.MyDisplayRouteInfo(id);
    }
}

MyDisplayRouteInfo是由RouteInfo NuGet 套件提供,並顯示路由資訊。MyDisplayRouteInfo is provided by the Rick.Docs.Samples.RouteInfo NuGet package and displays route information.

的執行 MyCustomConstraint 會防止套用 0 至路由參數:The implementation of MyCustomConstraint prevents 0 being applied to a route parameter:

class MyCustomConstraint : IRouteConstraint
{
    private Regex _regex;

    public MyCustomConstraint()
    {
        _regex = new Regex(@"^[1-9]*$",
                            RegexOptions.CultureInvariant | RegexOptions.IgnoreCase,
                            TimeSpan.FromMilliseconds(100));
    }
    public bool Match(HttpContext httpContext, IRouter route, string routeKey,
                      RouteValueDictionary values, RouteDirection routeDirection)
    {
        if (values.TryGetValue(routeKey, out object value))
        {
            var parameterValueString = Convert.ToString(value,
                                                        CultureInfo.InvariantCulture);
            if (parameterValueString == null)
            {
                return false;
            }

            return _regex.IsMatch(parameterValueString);
        }

        return false;
    }
}

警告

當使用System.Text.RegularExpressions來處理不受信任的輸入時,請傳遞超時。When using System.Text.RegularExpressions to process untrusted input, pass a timeout. 惡意使用者可以提供輸入, RegularExpressions導致拒絕服務攻擊A malicious user can provide input to RegularExpressions causing a Denial-of-Service attack. 使用RegularExpressions的 ASP.NET Core framework api 會傳遞超時。ASP.NET Core framework APIs that use RegularExpressions pass a timeout.

上述程式碼:The preceding code:

  • 防止 0{id} 路由的區段中。Prevents 0 in the {id} segment of the route.
  • 會顯示以提供執行自訂條件約束的基本範例。Is shown to provide a basic example of implementing a custom constraint. 不應在生產應用程式中使用。It should not be used in a production app.

下列程式碼是避免 id 處理包含之的較佳方法 0The following code is a better approach to preventing an id containing a 0 from being processed:

[HttpGet("{id}")]
public IActionResult Get(string id)
{
    if (id.Contains('0'))
    {
        return StatusCode(StatusCodes.Status406NotAcceptable);
    }

    return ControllerContext.MyDisplayRouteInfo(id);
}

上述程式碼在此方法上具有下列優點 MyCustomConstraintThe preceding code has the following advantages over the MyCustomConstraint approach:

  • 不需要自訂條件約束。It doesn't require a custom constraint.
  • 當路由參數包含時,它會傳回更具描述性的錯誤 0It returns a more descriptive error when the route parameter includes 0.

參數轉換器參考Parameter transformer reference

參數轉換程式:Parameter transformers:

例如,具有 Url.Action(new { article = "MyTestArticle" }) 之路由模式 blog\{article:slugify} 中的自訂 slugify 參數轉換器,會產生 blog\my-test-articleFor example, a custom slugify parameter transformer in route pattern blog\{article:slugify} with Url.Action(new { article = "MyTestArticle" }) generates blog\my-test-article.

請考慮下列執行 IOutboundParameterTransformerConsider the following IOutboundParameterTransformer implementation:

public class SlugifyParameterTransformer : IOutboundParameterTransformer
{
    public string TransformOutbound(object value)
    {
        if (value == null) { return null; }

        return Regex.Replace(value.ToString(), 
                             "([a-z])([A-Z])",
                             "$1-$2",
                             RegexOptions.CultureInvariant,
                             TimeSpan.FromMilliseconds(100)).ToLowerInvariant();
    }
}

若要在路由模式中使用參數轉換器,請使用中的來設定它 ConstraintMap Startup.ConfigureServicesTo use a parameter transformer in a route pattern, configure it using ConstraintMap in Startup.ConfigureServices:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();

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

ASP.NET Core framework 會使用參數轉換器來轉換端點解析的 URI。The ASP.NET Core framework uses parameter transformers to transform the URI where an endpoint resolves. 例如,參數轉換器會轉換用來比對 area 、、和的路由值 controller action pageFor example, parameter transformers transform the route values used to match an area, controller, action, and page.

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

使用上述路由範本,動作 SubscriptionManagementController.GetAll 會與 URI 相符 /subscription-management/get-allWith the preceding route template, the action SubscriptionManagementController.GetAll is matched with the URI /subscription-management/get-all. 參數轉換器不會變更用來產生連結的路由值。A parameter transformer doesn't change the route values used to generate a link. 例如,Url.Action("GetAll", "SubscriptionManagement") 會輸出 /subscription-management/get-allFor example, Url.Action("GetAll", "SubscriptionManagement") outputs /subscription-management/get-all.

ASP.NET Core 提供使用參數轉換器搭配產生的路由的 API 慣例:ASP.NET Core provides API conventions for using parameter transformers with generated routes:

URL 產生參考URL generation reference

此章節包含 URL 產生所實作為演算法的參考。This section contains a reference for the algorithm implemented by URL generation. 實際上,最複雜的 URL 產生範例會使用控制器或 Razor 頁面。In practice, most complex examples of URL generation use controllers or Razor Pages. 如需其他資訊,請參閱控制器中的路由See routing in controllers for additional information.

URL 產生進程會從呼叫LinkGenerator. GetPathByAddress或類似的方法開始。The URL generation process begins with a call to LinkGenerator.GetPathByAddress or a similar method. 提供的方法包含位址、一組路由值,以及來自的目前要求的選擇性資訊 HttpContextThe method is provided with an address, a set of route values, and optionally information about the current request from HttpContext.

第一個步驟是使用位址來解析一組候選端點,並使用 IEndpointAddressScheme<TAddress> 符合網址類別型的。The first step is to use the address to resolve a set of candidate endpoints using an IEndpointAddressScheme<TAddress> that matches the address's type.

位址配置找到一組候選項目之後,就會反復排序並處理端點,直到 URL 產生作業成功為止。Once of set of candidates is found by the address scheme, the endpoints are ordered and processed iteratively until a URL generation operation succeeds. URL產生不會檢查是否有多義性,傳回的第一個結果是最終的結果。URL generation does not check for ambiguities, the first result returned is the final result.

使用記錄進行 URL 產生的疑難排解Troubleshooting URL generation with logging

針對 URL 產生進行疑難排解的第一個步驟是將的記錄層級設定 Microsoft.AspNetCore.RoutingTRACEThe first step in troubleshooting URL generation is setting the logging level of Microsoft.AspNetCore.Routing to TRACE. LinkGenerator記錄其處理的許多詳細資料,這有助於疑難排解問題。LinkGenerator logs many details about its processing which can be useful to troubleshoot problems.

如需 URL 產生的詳細資訊,請參閱url 產生參考See URL generation reference for details on URL generation.

位址Addresses

位址是 URL 產生的概念,用來將連結產生器的呼叫系結至一組候選端點。Addresses are the concept in URL generation used to bind a call into the link generator to a set of candidate endpoints.

位址是一種可延伸的概念,預設會隨附兩個執行:Addresses are an extensible concept that come with two implementations by default:

  • 使用端點名稱 (string) 作為位址:Using endpoint name (string) as the address:
    • 為 MVC 的路由名稱提供類似的功能。Provides similar functionality to MVC's route name.
    • 使用 IEndpointNameMetadata 元資料類型。Uses the IEndpointNameMetadata metadata type.
    • 針對所有已註冊端點的中繼資料,解析提供的字串。Resolves the provided string against the metadata of all registered endpoints.
    • 如果多個端點使用相同的名稱,則會在啟動時擲回例外狀況。Throws an exception on startup if multiple endpoints use the same name.
    • 建議用於在控制器和頁面以外的一般用途 Razor 。Recommended for general-purpose use outside of controllers and Razor Pages.
  • 使用路由值 (RouteValuesAddress) 作為位址:Using route values (RouteValuesAddress) as the address:
    • 提供類似的功能來進行控制器和 Razor 分頁的舊版 URL 產生。Provides similar functionality to controllers and Razor Pages legacy URL generation.
    • 擴充和調試非常複雜。Very complex to extend and debug.
    • 提供所使用的實作為 IUrlHelper 、標記協助程式、HTML helper、動作結果等。Provides the implementation used by IUrlHelper, Tag Helpers, HTML Helpers, Action Results, etc.

位址配置的角色是讓位址和相符端點之間的關聯依照任意準則:The role of the address scheme is to make the association between the address and matching endpoints by arbitrary criteria:

  • 端點名稱配置會執行基本的字典查閱。The endpoint name scheme performs a basic dictionary lookup.
  • 路由值配置具有集合演算法的複雜最佳子集。The route values scheme has a complex best subset of set algorithm.

環境值和明確的值Ambient values and explicit values

根據目前的要求,路由會存取目前要求的路由值 HttpContext.Request.RouteValuesFrom the current request, routing accesses the route values of the current request HttpContext.Request.RouteValues. 與目前要求相關聯的值稱為「環境值」。The values associated with the current request are referred to as the ambient values. 為了清楚起見,檔是指傳遞至方法做為明確值的路由值。For the purpose of clarity, the documentation refers to the route values passed in to methods as explicit values.

下列範例會顯示環境值和明確的值。The following example shows ambient values and explicit values. 它會從目前的要求和明確的值中提供環境 { id = 17, } 值:It provides ambient values from the current request and explicit values: { id = 17, }:

public class WidgetController : Controller
{
    private readonly LinkGenerator _linkGenerator;

    public WidgetController(LinkGenerator linkGenerator)
    {
        _linkGenerator = linkGenerator;
    }

    public IActionResult Index()
    {
        var url = _linkGenerator.GetPathByAction(HttpContext,
                                                 null, null,
                                                 new { id = 17, });
        return Content(url);
    }

上述程式碼:The preceding code:

下列程式碼不會提供環境值和明確的 { controller = "Home", action = "Subscribe", id = 17, } 值:The following code provides no ambient values and explicit values: { controller = "Home", action = "Subscribe", id = 17, }:

public IActionResult Index2()
{
    var url = _linkGenerator.GetPathByAction("Subscribe", "Home",
                                             new { id = 17, });
    return Content(url);
}

上述方法會傳回/Home/Subscribe/17The preceding method returns /Home/Subscribe/17

中的下列程式碼會傳回 WidgetController /Widget/Subscribe/17The following code in the WidgetController returns /Widget/Subscribe/17:

var url = _linkGenerator.GetPathByAction("Subscribe", null,
                                         new { id = 17, });

下列程式碼會從目前要求中的環境值和明確值提供 { action = "Edit", id = 17, } 控制器:The following code provides the controller from ambient values in the current request and explicit values: { action = "Edit", id = 17, }:

public class GadgetController : Controller
{
    public IActionResult Index()
    {
        var url = Url.Action("Edit", new { id = 17, });
        return Content(url);
    }

在上述程式碼中:In the preceding code:

  • /Gadget/Edit/17傳回。/Gadget/Edit/17 is returned.
  • Url取得 IUrlHelperUrl gets the IUrlHelper.
  • Action
    產生具有動作方法之絕對路徑的 URL。generates a URL with an absolute path for an action method. URL 包含指定的 action 名稱和 route 值。The URL contains the specified action name and route values.

下列程式碼提供來自目前要求和明確值的環境 { page = "./Edit, id = 17, } 值:The following code provides ambient values from the current request and explicit values: { page = "./Edit, id = 17, }:

public class IndexModel : PageModel
{
    public void OnGet()
    {
        var url = Url.Page("./Edit", new { id = 17, });
        ViewData["URL"] = url;
    }
}

上述程式碼會 url/Edit/17 [編輯] Razor 頁面包含下列頁面指示詞時,將設為:The preceding code sets url to /Edit/17 when the Edit Razor Page contains the following page directive:

@page "{id:int}"

如果 [編輯] 頁面不包含 "{id:int}" 路由範本, url 則為 /Edit?id=17If the Edit page doesn't contain the "{id:int}" route template, url is /Edit?id=17.

IUrlHelper除了此處所述的規則之外,MVC 的行為也會增加一層複雜度:The behavior of MVC's IUrlHelper adds a layer of complexity in addition to the rules described here:

  • IUrlHelper一律會提供來自目前要求的路由值做為環境值。IUrlHelper always provides the route values from the current request as ambient values.
  • IUrlHelper一律會將目前的 actioncontroller 路由值複製成明確的值,除非由開發人員覆寫。IUrlHelper.Action always copies the current action and controller route values as explicit values unless overridden by the developer.
  • IUrlHelper一律會將目前的 page 路由值複製成明確的值,除非予以覆寫。IUrlHelper.Page always copies the current page route value as an explicit value unless overridden.
  • IUrlHelper.Page除非覆寫,否則一律會以明確的值覆寫目前的 handler 路由值 nullIUrlHelper.Page always overrides the current handler route value with null as an explicit values unless overridden.

使用者通常會因為環境值的行為詳細資料而感到驚訝,因為 MVC 似乎不會遵循其本身的規則。Users are often surprised by the behavioral details of ambient values, because MVC doesn't seem to follow its own rules. 基於歷史和相容性的原因,某些路由值(例如 actioncontrollerpage 和) handler 有自己的特殊案例行為。For historical and compatibility reasons, certain route values such as action, controller, page, and handler have their own special-case behavior.

所提供的對等功能 LinkGenerator.GetPathByAction ,會 LinkGenerator.GetPathByPage 複製這些異常的 IUrlHelper 以實現相容性。The equivalent functionality provided by LinkGenerator.GetPathByAction and LinkGenerator.GetPathByPage duplicates these anomalies of IUrlHelper for compatibility.

URL 產生進程URL generation process

一旦找到候選端點集合之後,URL 產生演算法就會:Once the set of candidate endpoints are found, the URL generation algorithm:

  • 反復處理端點。Processes the endpoints iteratively.
  • 傳回第一個成功的結果。Returns the first successful result.

此程式的第一個步驟是所謂的路由值失效The first step in this process is called route value invalidation. 路由值失效是路由決定應該使用哪些來自環境值的路由值以及應該忽略的進程。Route value invalidation is the process by which routing decides which route values from the ambient values should be used and which should be ignored. 會考慮每個環境值,並將其與明確值結合,或予以忽略。Each ambient value is considered and either combined with the explicit values, or ignored.

考慮環境值角色的最佳方式,就是他們會嘗試儲存應用程式開發人員在某些常見的情況下輸入。The best way to think about the role of ambient values is that they attempt to save application developers typing, in some common cases. 傳統上,環境值很有用的案例與 MVC 相關:Traditionally, the scenarios where ambient values are helpful are related to MVC:

  • 連結至相同控制器中的另一個動作時,不需要指定控制器名稱。When linking to another action in the same controller, the controller name doesn't need to be specified.
  • 連結至相同區域中的另一個控制器時,不需要指定區功能變數名稱稱。When linking to another controller in the same area, the area name doesn't need to be specified.
  • 連結至相同的動作方法時,不需要指定路由值。When linking to the same action method, route values don't need to be specified.
  • 當連結到應用程式的另一個部分時,您不會想要在應用程式的該部分中執行不具意義的路由值。When linking to another part of the app, you don't want to carry over route values that have no meaning in that part of the app.

呼叫 LinkGenerator 或傳回 IUrlHelpernull 通常是因為不了解路由值失效所造成。Calls to LinkGenerator or IUrlHelper that return null are usually caused by not understanding route value invalidation. 明確指定更多的路由值,以查看是否能解決問題,以針對路由值失效進行疑難排解。Troubleshoot route value invalidation by explicitly specifying more of the route values to see if that solves the problem.

路由值失效的假設是應用程式的 URL 配置是階層式的,並以從左至右形成的階層。Route value invalidation works on the assumption that the app's URL scheme is hierarchical, with a hierarchy formed from left-to-right. 請考慮使用「基本控制器路由」範本 {controller}/{action}/{id?} ,以直覺的方式來瞭解這在實務上如何運作。Consider the basic controller route template {controller}/{action}/{id?} to get an intuitive sense of how this works in practice. 值的變更會使顯示在右側的所有路由值失效A change to a value invalidates all of the route values that appear to the right. 這反映了關於階層的假設。This reflects the assumption about hierarchy. 如果應用程式具有的環境值 id ,且作業為指定了不同的值 controllerIf the app has an ambient value for id, and the operation specifies a different value for the controller:

  • id不會重複使用 {controller} ,因為位於的左邊 {id?}id won't be reused because {controller} is to the left of {id?}.

示範此原則的一些範例如下:Some examples demonstrating this principle:

  • 如果明確的值包含的值 id ,則會忽略的環境值 idIf the explicit values contain a value for id, the ambient value for id is ignored. controller 可以使用和的環境值 actionThe ambient values for controller and action can be used.
  • 如果明確的值包含的值 action ,則會忽略的任何環境值 actionIf the explicit values contain a value for action, any ambient value for action is ignored. 可以使用的環境值 controllerThe ambient values for controller can be used. 如果的明確值與 action 的環境值不同 action ,則 id 不會使用此值。If the explicit value for action is different from the ambient value for action, the id value won't be used. 如果的明確值與 action 的環境值相同 action ,則 id 可以使用值。If the explicit value for action is the same as the ambient value for action, the id value can be used.
  • 如果明確的值包含的值 controller ,則會忽略的任何環境值 controllerIf the explicit values contain a value for controller, any ambient value for controller is ignored. 如果的明確值與 controller 的環境值不同 controller ,則 action id 不會使用和值。If the explicit value for controller is different from the ambient value for controller, the action and id values won't be used. 如果的明確值與 controller 的環境值相同 controller ,則 action id 可以使用和值。If the explicit value for controller is the same as the ambient value for controller, the action and id values can be used.

這個程式會因為屬性路由的存在和專用的慣例路由而變得更複雜。This process is further complicated by the existence of attribute routes and dedicated conventional routes. 控制器慣例路由,例如 {controller}/{action}/{id?} 使用路由參數來指定階層。Controller conventional routes such as {controller}/{action}/{id?} specify a hierarchy using route parameters. 針對專用的傳統路由,以及控制器和頁面的屬性路由 Razor :For dedicated conventional routes and attribute routes to controllers and Razor Pages:

  • 有路由值的階層。There is a hierarchy of route values.
  • 它們不會出現在範本中。They don't appear in the template.

在這些情況下,URL 產生會定義必要的值概念。For these cases, URL generation defines the required values concept. 控制器和頁面所建立的端點, Razor 所指定的必要值可讓路由值失效。Endpoints created by controllers and Razor Pages have required values specified that allow route value invalidation to work.

路由值失效演算法詳細資料:The route value invalidation algorithm in detail:

  • 必要的值名稱會與路由參數結合,然後由左至右處理。The required value names are combined with the route parameters, then processed from left-to-right.
  • 針對每個參數,會比較環境值和明確的值:For each parameter, the ambient value and explicit value are compared:
    • 如果環境值和明確的值相同,則進程會繼續進行。If the ambient value and explicit value are the same, the process continues.
    • 如果環境值存在且明確的值不是,則會在產生 URL 時使用環境值。If the ambient value is present and the explicit value isn't, the ambient value is used when generating the URL.
    • 如果環境值不存在,且明確的值為,則會拒絕環境值和所有後續的環境值。If the ambient value isn't present and the explicit value is, reject the ambient value and all subsequent ambient values.
    • 如果環境值和明確值存在,而且這兩個值不同,則會拒絕環境值和所有後續的環境值。If the ambient value and the explicit value are present, and the two values are different, reject the ambient value and all subsequent ambient values.

此時,URL 產生作業已準備好評估路由條件約束。At this point, the URL generation operation is ready to evaluate route constraints. 一組接受的值會與提供給條件約束的參數預設值結合。The set of accepted values is combined with the parameter default values, which is provided to constraints. 如果條件約束都通過,作業就會繼續。If the constraints all pass, the operation continues.

接下來,可以使用接受的值來展開路由範本。Next, the accepted values can be used to expand the route template. 會處理路由範本:The route template is processed:

  • 從左至右。From left-to-right.
  • 每個參數都有其接受的值取代。Each parameter has its accepted value substituted.
  • 有下列特殊案例:With the following special cases:
    • 如果接受的值遺漏值,且參數具有預設值,則會使用預設值。If the accepted values is missing a value and the parameter has a default value, the default value is used.
    • 如果接受的值遺漏值,而且參數是選擇性的,則會繼續處理。If the accepted values is missing a value and the parameter is optional, processing continues.
    • 如果遺漏選擇性參數右邊的任何路由參數具有值,則作業會失敗。If any route parameter to the right of a missing optional parameter has a value, the operation fails.
    • 連續的預設值參數和選擇性參數會盡可能折迭。Contiguous default-valued parameters and optional parameters are collapsed where possible.

明確提供並不符合路由區段的值會新增至查詢字串。Values explicitly provided that don't match a segment of the route are added to the query string. 下表顯示使用路由範本 {controller}/{action}/{id?} 時的結果。The following table shows the result when using the route template {controller}/{action}/{id?}.

環境值Ambient Values 明確值Explicit Values 結果Result
controller = "Home"controller = "Home" action = "About"action = "About" /Home/About
controller = "Home"controller = "Home" controller = "Order", action = "About"controller = "Order", action = "About" /Order/About
controller = "Home", color = "Red"controller = "Home", color = "Red" action = "About"action = "About" /Home/About
controller = "Home"controller = "Home" action = "About", color = "Red"action = "About", color = "Red" /Home/About?color=Red

路由值失效的問題Problems with route value invalidation

從 ASP.NET Core 3.0,先前 ASP.NET Core 版本中使用的某些 URL 產生配置,不適用於 URL 產生的效果。As of ASP.NET Core 3.0, some URL generation schemes used in earlier ASP.NET Core versions don't work well with URL generation. ASP.NET Core 小組計畫在未來的版本中新增功能,以解決這些需求。The ASP.NET Core team plans to add features to address these needs in a future release. 現在最好的解決方案是使用舊版路由。For now the best solution is to use legacy routing.

下列程式碼顯示路由不支援的 URL 產生配置範例。The following code shows an example of a URL generation scheme that's not supported by routing.

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute("default", 
                                     "{culture}/{controller=Home}/{action=Index}/{id?}");
    endpoints.MapControllerRoute("blog", "{culture}/{**slug}", 
                                      new { controller = "Blog", action = "ReadPost", });
});

在上述程式碼中, culture route 參數是用於當地語系化。In the preceding code, the culture route parameter is used for localization. 想要讓 culture 參數一律接受為環境值。The desire is to have the culture parameter always accepted as an ambient value. 不過, culture 因為必要值的使用方式,所以不接受參數作為環境值:However, the culture parameter is not accepted as an ambient value because of the way required values work:

  • "default" 路由範本中, culture 路由參數是在的左邊 controller ,因此變更 controller 不會使失效 cultureIn the "default" route template, the culture route parameter is to the left of controller, so changes to controller won't invalidate culture.
  • "blog" 路由範本中, culture 路由參數會被視為位於的右邊 controller ,這會出現在必要的值中。In the "blog" route template, the culture route parameter is considered to be to the right of controller, which appears in the required values.

設定端點中繼資料Configuring endpoint metadata

下列連結提供設定端點中繼資料的相關資訊:The following links provide information on configuring endpoint metadata:

搭配 RequireHost 的路由中的主機比對Host matching in routes with RequireHost

RequireHost將條件約束套用至需要指定之主控制項的路由。RequireHost applies a constraint to the route which requires the specified host. RequireHost[Host]參數可以是:The RequireHost or [Host] parameter can be:

  • 主機: www.domain.com ,符合 www.domain.com 任何埠。Host: www.domain.com, matches www.domain.com with any port.
  • 具有萬用字元的主機: *.domain.com 、符合 www.domain.comsubdomain.domain.comwww.subdomain.domain.com 任何埠上的。Host with wildcard: *.domain.com, matches www.domain.com, subdomain.domain.com, or www.subdomain.domain.com on any port.
  • 埠: *:5000 ,符合任何主機的通訊埠5000。Port: *:5000, matches port 5000 with any host.
  • 主機和埠: www.domain.com:5000*.domain.com:5000 符合主機和埠。Host and port: www.domain.com:5000 or *.domain.com:5000, matches host and port.

您可以使用或來指定多個參數 RequireHost [Host]Multiple parameters can be specified using RequireHost or [Host]. 條件約束符合任何參數的有效主機。The constraint matches hosts valid for any of the parameters. 例如,會比對 [Host("domain.com", "*.domain.com")] domain.comwww.domain.comsubdomain.domain.comFor example, [Host("domain.com", "*.domain.com")] matches domain.com, www.domain.com, and subdomain.domain.com.

下列程式碼會使用 RequireHost 來要求路由上指定的主機:The following code uses RequireHost to require the specified host on the route:

public void Configure(IApplicationBuilder app)
{
    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapGet("/", context => context.Response.WriteAsync("Hi Contoso!"))
            .RequireHost("contoso.com");
        endpoints.MapGet("/", context => context.Response.WriteAsync("AdventureWorks!"))
            .RequireHost("adventure-works.com");
        endpoints.MapHealthChecks("/healthz").RequireHost("*:8080");
    });
}

下列程式碼會在 [Host] 控制器上使用屬性來要求任何指定的主機:The following code uses the [Host] attribute on the controller to require any of the specified hosts:

[Host("contoso.com", "adventure-works.com")]
public class ProductController : Controller
{
    public IActionResult Index()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }

    [Host("example.com:8080")]
    public IActionResult Privacy()
    {
        return ControllerContext.MyDisplayRouteInfo();
    }
}

[Host] 屬性同時套用至控制器和動作方法時:When the [Host] attribute is applied to both the controller and action method:

  • 會使用動作上的屬性。The attribute on the action is used.
  • 已忽略控制器屬性。The controller attribute is ignored.

路由的效能指引Performance guidance for routing

大部分的路由都已在 ASP.NET Core 3.0 中更新,以提高效能。Most of routing was updated in ASP.NET Core 3.0 to increase performance.

當應用程式發生效能問題時,通常會懷疑路由是問題。When an app has performance problems, routing is often suspected as the problem. 路由的原因是,控制器和頁面之類的架構,會 Razor 回報在其記錄訊息內所花費的時間量。The reason routing is suspected is that frameworks like controllers and Razor Pages report the amount of time spent inside the framework in their logging messages. 當控制器回報的時間與要求的總時間之間有顯著的差異時:When there's a significant difference between the time reported by controllers and the total time of the request:

  • 開發人員會將其應用程式程式碼排除為問題的來源。Developers eliminate their app code as the source of the problem.
  • 通常會假設路由是原因。It's common to assume routing is the cause.

路由會使用數千個端點來測試效能。Routing is performance tested using thousands of endpoints. 一般的應用程式不太可能會遇到太大的效能問題。It's unlikely that a typical app will encounter a performance problem just by being too large. 緩慢路由效能最常見的根本原因通常是行為不佳的自訂中介軟體。The most common root cause of slow routing performance is usually a badly-behaving custom middleware.

下列程式碼範例示範縮小延遲來源的基本技巧:This following code sample demonstrates a basic technique for narrowing down the source of delay:

public void Configure(IApplicationBuilder app, ILogger<Startup> logger)
{
    app.Use(next => async context =>
    {
        var sw = Stopwatch.StartNew();
        await next(context);
        sw.Stop();

        logger.LogInformation("Time 1: {ElapsedMilliseconds}ms", sw.ElapsedMilliseconds);
    });

    app.UseRouting();

    app.Use(next => async context =>
    {
        var sw = Stopwatch.StartNew();
        await next(context);
        sw.Stop();

        logger.LogInformation("Time 2: {ElapsedMilliseconds}ms", sw.ElapsedMilliseconds);
    });

    app.UseAuthorization();

    app.Use(next => async context =>
    {
        var sw = Stopwatch.StartNew();
        await next(context);
        sw.Stop();

        logger.LogInformation("Time 3: {ElapsedMilliseconds}ms", sw.ElapsedMilliseconds);
    });

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapGet("/", async context =>
        {
            await context.Response.WriteAsync("Timing test.");
        });
    });
}

若要進行時間路由:To time routing:

  • 使用上述程式碼中所示的計時中介軟體複本來交錯每個中介軟體。Interleave each middleware with a copy of the timing middleware shown in the preceding code.
  • 新增唯一識別碼,將計時資料與程式碼相互關聯。Add a unique identifier to correlate the timing data with the code.

這是將延遲縮小到最大的基本方式,例如,超過 10msThis is a basic way to narrow down the delay when it's significant, for example, more than 10ms. Time 2Time 1 報表減去中介軟體內所花費的時間 UseRoutingSubtracting Time 2 from Time 1 reports the time spent inside the UseRouting middleware.

下列程式碼會針對上述計時程式碼使用更精簡的方法:The following code uses a more compact approach to the preceding timing code:

public sealed class MyStopwatch : IDisposable
{
    ILogger<Startup> _logger;
    string _message;
    Stopwatch _sw;

    public MyStopwatch(ILogger<Startup> logger, string message)
    {
        _logger = logger;
        _message = message;
        _sw = Stopwatch.StartNew();
    }

    private bool disposed = false;


    public void Dispose()
    {
        if (!disposed)
        {
            _logger.LogInformation("{Message }: {ElapsedMilliseconds}ms",
                                    _message, _sw.ElapsedMilliseconds);

            disposed = true;
        }
    }
}
public void Configure(IApplicationBuilder app, ILogger<Startup> logger)
{
    int count = 0;
    app.Use(next => async context =>
    {
        using (new MyStopwatch(logger, $"Time {++count}"))
        {
            await next(context);
        }

    });

    app.UseRouting();

    app.Use(next => async context =>
    {
        using (new MyStopwatch(logger, $"Time {++count}"))
        {
            await next(context);
        }
    });

    app.UseAuthorization();

    app.Use(next => async context =>
    {
        using (new MyStopwatch(logger, $"Time {++count}"))
        {
            await next(context);
        }
    });

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapGet("/", async context =>
        {
            await context.Response.WriteAsync("Timing test.");
        });
    });
}

可能昂貴的路由功能Potentially expensive routing features

下列清單提供一些路由功能的深入解析,相較于基本的路由範本,這會相當耗費資源:The following list provides some insight into routing features that are relatively expensive compared with basic route templates:

  • 正則運算式:可以撰寫複雜的正則運算式,或具有少量輸入的長期執行時間。Regular expressions: It's possible to write regular expressions that are complex, or have long running time with a small amount of input.

  • () 的複雜區段 {x}-{y}-{z}Complex segments ({x}-{y}-{z}):

    • 比剖析一般 URL 路徑區段高得多。Are significantly more expensive than parsing a regular URL path segment.
    • 導致已配置更多子字串。Result in many more substrings being allocated.
    • 在 ASP.NET Core 3.0 路由效能更新中,未更新複雜的區段邏輯。The complex segment logic was not updated in ASP.NET Core 3.0 routing performance update.
  • 同步資料存取:許多複雜的應用程式在其路由中都具有資料庫存取權。Synchronous data access: Many complex apps have database access as part of their routing. ASP.NET Core 2.2 和較舊的路由可能不會提供支援資料庫存取路由的正確擴充點。ASP.NET Core 2.2 and earlier routing might not provide the right extensibility points to support database access routing. 例如,、 IRouteConstraintIActionConstraint 都是同步的。For example, IRouteConstraint, and IActionConstraint are synchronous. 和等擴充點 MatcherPolicy EndpointSelectorContext 都是非同步。Extensibility points such as MatcherPolicy and EndpointSelectorContext are asynchronous.

程式庫作者指引Guidance for library authors

本章節包含程式庫作者在路由之上建立的指導方針。This section contains guidance for library authors building on top of routing. 這些詳細資料的目的是要確保應用程式開發人員能夠使用延伸路由的程式庫和架構。These details are intended to ensure that app developers have a good experience using libraries and frameworks that extend routing.

定義端點Define endpoints

若要建立使用路由進行 URL 比對的架構,請先定義以為基礎的使用者體驗 UseEndpointsTo create a framework that uses routing for URL matching, start by defining a user experience that builds on top of UseEndpoints.

在之上建立組建 IEndpointRouteBuilderDO build on top of IEndpointRouteBuilder. 這可讓使用者使用其他 ASP.NET Core 功能來撰寫您的架構,而不會造成混淆。This allows users to compose your framework with other ASP.NET Core features without confusion. 每個 ASP.NET Core 範本都包含路由。Every ASP.NET Core template includes routing. 假設路由存在且熟悉使用者。Assume routing is present and familiar for users.

app.UseEndpoints(endpoints =>
{
    // Your framework
    endpoints.MapMyFramework(...);

    endpoints.MapHealthChecks("/healthz");
});

確實從對所執行的呼叫傳回密封的實體型別 MapMyFramework(...) IEndpointConventionBuilderDO return a sealed concrete type from a call to MapMyFramework(...) that implements IEndpointConventionBuilder. 大部分 Map... 的架構方法會遵循此模式。Most framework Map... methods follow this pattern. IEndpointConventionBuilder介面:The IEndpointConventionBuilder interface:

  • 允許複合性中繼資料。Allows composability of metadata.
  • 的目標是各種擴充方法。Is targeted by a variety of extension methods.

宣告您自己的型別可讓您將自己的架構特定功能加入至產生器。Declaring your own type allows you to add your own framework-specific functionality to the builder. 將架構宣告的產生器和轉送呼叫包裝在一起是正常的。It's ok to wrap a framework-declared builder and forward calls to it.

app.UseEndpoints(endpoints =>
{
    // Your framework
    endpoints.MapMyFramework(...).RequireAuthorization()
                                 .WithMyFrameworkFeature(awesome: true);

    endpoints.MapHealthChecks("/healthz");
});

請考慮撰寫自己 EndpointDataSource 的。CONSIDER writing your own EndpointDataSource. EndpointDataSource是用來宣告和更新端點集合的低層級基本類型。EndpointDataSource is the low-level primitive for declaring and updating a collection of endpoints. EndpointDataSource是控制器和頁面所使用的強大 API Razor 。EndpointDataSource is a powerful API used by controllers and Razor Pages.

路由測試有一個不會更新資料來源的基本範例The routing tests have a basic example of a non-updating data source.

預設不會嘗試註冊 EndpointDataSourceDO NOT attempt to register an EndpointDataSource by default. 要求使用者在中註冊您的架構 UseEndpointsRequire users to register your framework in UseEndpoints. 路由的原理是預設不會包含任何內容,也 UseEndpoints 就是註冊端點的位置。The philosophy of routing is that nothing is included by default, and that UseEndpoints is the place to register endpoints.

建立路由整合中介軟體Creating routing-integrated middleware

請考慮將元資料類型定義為介面。CONSIDER defining metadata types as an interface.

您可以使用中繼資料類型做為類別和方法上的屬性。DO make it possible to use metadata types as an attribute on classes and methods.

public interface ICoolMetadata
{
    bool IsCool { get; }
}

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class CoolMetadataAttribute : Attribute, ICoolMetadata
{
    public bool IsCool => true;
}

控制器和頁面之類 Razor 的架構支援將中繼資料屬性套用至類型和方法。Frameworks like controllers and Razor Pages support applying metadata attributes to types and methods. 如果您宣告元資料類型:If you declare metadata types:

  • 使其可做為屬性存取。Make them accessible as attributes.
  • 大部分的使用者都很熟悉套用屬性。Most users are familiar with applying attributes.

將元資料類型宣告為介面,會增加另一層彈性:Declaring a metadata type as an interface adds another layer of flexibility:

  • 介面是可組合的。Interfaces are composable.
  • 開發人員可以宣告自己的類型,結合多個原則。Developers can declare their own types that combine multiple policies.

確實能夠覆寫中繼資料,如下列範例所示:DO make it possible to override metadata, as shown in the following example:

public interface ICoolMetadata
{
    bool IsCool { get; }
}

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class CoolMetadataAttribute : Attribute, ICoolMetadata
{
    public bool IsCool => true;
}

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class SuppressCoolMetadataAttribute : Attribute, ICoolMetadata
{
    public bool IsCool => false;
}

[CoolMetadata]
public class MyController : Controller
{
    public void MyCool() { }

    [SuppressCoolMetadata]
    public void Uncool() { }
}

遵循這些指導方針的最佳方式是避免定義標記中繼資料The best way to follow these guidelines is to avoid defining marker metadata:

  • 請不要只尋找元資料類型是否存在。Don't just look for the presence of a metadata type.
  • 在中繼資料上定義屬性,並檢查屬性。Define a property on the metadata and check the property.

元資料集合會進行排序,並依優先順序支援覆寫。The metadata collection is ordered and supports overriding by priority. 在控制器的案例中,動作方法上的中繼資料是最明確的。In the case of controllers, metadata on the action method is most specific.

讓中間件適用于且不使用路由。DO make middleware useful with and without routing.

app.UseRouting();

app.UseAuthorization(new AuthorizationPolicy() { ... });

app.UseEndpoints(endpoints =>
{
    // Your framework
    endpoints.MapMyFramework(...).RequireAuthorization();
});

作為此指導方針的範例,請考慮 UseAuthorization 中介軟體。As an example of this guideline, consider the UseAuthorization middleware. 授權中介軟體可讓您傳入回退原則。The authorization middleware allows you to pass in a fallback policy. 如果指定了回溯原則,則會套用至兩者:The fallback policy, if specified, applies to both:

  • 沒有指定之原則的端點。Endpoints without a specified policy.
  • 不符合端點的要求。Requests that don't match an endpoint.

這可讓授權中介軟體適用于路由內容以外的地方。This makes the authorization middleware useful outside of the context of routing. 授權中介軟體可用於傳統中介軟體程式設計。The authorization middleware can be used for traditional middleware programming.

偵錯工具診斷Debug diagnostics

如需詳細的路由診斷輸出,請將設定 Logging:LogLevel:MicrosoftDebugFor detailed routing diagnostic output, set Logging:LogLevel:Microsoft to Debug. 在開發環境中,將appsettings.Development.js中的記錄層級設定為onIn the development environment, set the log level in appsettings.Development.json:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Debug",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  }
}

路由會負責將要求 Uri 對應至端點,並將傳入要求分派至這些端點。Routing is responsible for mapping request URIs to endpoints and dispatching incoming requests to those endpoints. 路由定義於應用程式,並在該應用程式啟動時進行設定。Routes are defined in the app and configured when the app starts. 路由可以選擇性地從要求中所包含的 URL 擷取值,然後這些值就可用於處理要求。A route can optionally extract values from the URL contained in the request, and these values can then be used for request processing. 使用來自應用程式的路由資訊,路由也能夠產生對應至端點的 Url。Using route information from the app, routing is also able to generate URLs that map to endpoints.

若要使用 ASP.NET Core 2.2 中的最新路由情節,請將相容性版本指定為 Startup.ConfigureServices 中的 MVC 服務註冊:To use the latest routing scenarios in ASP.NET Core 2.2, specify the compatibility version to the MVC services registration in Startup.ConfigureServices:

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

EnableEndpointRouting 選項會決定路由功能應該在內部使用以端點為基礎的邏輯,或以 IRouter 為基礎的邏輯 (適用於 ASP.NET Core 2.1 或更舊版本)。The EnableEndpointRouting option determines if routing should internally use endpoint-based logic or the IRouter-based logic of ASP.NET Core 2.1 or earlier. 當相容性版本設定為 2.2 或更新版本時,預設值為 trueWhen the compatibility version is set to 2.2 or later, the default value is true. 將值設定為 false 可使用舊版路由邏輯:Set the value to false to use the prior routing logic:

// Use the routing logic of ASP.NET Core 2.1 or earlier:
services.AddMvc(options => options.EnableEndpointRouting = false)
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

如需以 IRouter 為基礎之路由的詳細資訊,請參閱本主題的 ASP.NET Core 2.1 版本For more information on IRouter-based routing, see the ASP.NET Core 2.1 version of this topic.

重要

本文件涵蓋低階的 ASP.NET Core 路由。This document covers low-level ASP.NET Core routing. 如需 ASP.NET Core MVC 路由的資訊,請參閱 ASP.NET Core 中的路由至控制器動作For information on ASP.NET Core MVC routing, see ASP.NET Core 中的路由至控制器動作. 如需頁面中路由慣例的詳細資訊 Razor ,請參閱 RazorASP.NET Core 中的頁面路由和應用程式慣例For information on routing conventions in Razor Pages, see RazorASP.NET Core 中的頁面路由和應用程式慣例.

查看或下載範例程式碼 (如何下載) View or download sample code (how to download)

路由的基本概念Routing basics

大部分應用程式都應該選擇基本的描述性路由傳送配置,讓 URL 可讀且有意義。Most apps should choose a basic and descriptive routing scheme so that URLs are readable and meaningful. 預設慣例路由 {controller=Home}/{action=Index}/{id?}The default conventional route {controller=Home}/{action=Index}/{id?}:

  • 支援基本的描述性路由配置。Supports a basic and descriptive routing scheme.
  • 適合作為 UI 型應用程式的起點。Is a useful starting point for UI-based apps.

開發人員通常會使用屬性路由或專用的慣例路由,在特殊情況下,將額外的簡易路由新增到應用程式的高流量區域。Developers commonly add additional terse routes to high-traffic areas of an app in specialized situations using attribute routing or dedicated conventional routes. 特殊情況的範例包括: blog 和電子商務端點。Specialized situations examples include, blog and ecommerce endpoints.

Web API 應該使用屬性路由傳送來將應用程式功能模型建構為作業由 HTTP 指令動詞代表的資源集合。Web APIs should use attribute routing to model the app's functionality as a set of resources where operations are represented by HTTP verbs. 這表示相同邏輯資源上的許多作業(例如 GET 和 POST)都會使用相同的 URL。This means that many operations, for example, GET, and POST, on the same logical resource use the same URL. 屬性路由提供仔細設計 API 公用端點配置所需的控制層級。Attribute routing provides a level of control that's needed to carefully design an API's public endpoint layout.

Razor頁面應用程式會使用預設的傳統路由,在應用程式的Pages資料夾中提供已命名的資源。 Pages apps use default conventional routing to serve named resources in the Pages folder of an app. 還有其他慣例可讓您自訂 Razor 頁面路由行為。Additional conventions are available that allow you to customize Razor Pages routing behavior. 如需詳細資訊,請參閱 RazorASP.NET Core 中的頁面簡介RazorASP.NET Core 中的頁面路由和應用程式慣例For more information, see RazorASP.NET Core 中的頁面簡介 and RazorASP.NET Core 中的頁面路由和應用程式慣例.

URL 產生支援允許在不需要硬式編碼的 URL 來連結應用程式的情況下開發應用程式。URL generation support allows the app to be developed without hard-coding URLs to link the app together. 這項支援可讓您從基本路由設定開始,並在決定應用程式資源配置之後修改路由。This support allows for starting with a basic routing configuration and modifying the routes after the app's resource layout is determined.

路由會使用端點 (Endpoint) 來代表應用程式中的邏輯端點。Routing uses endpoints (Endpoint) to represent logical endpoints in an app.

端點會定義用來處理要求的一項委派及一個任意中繼資料集合。An endpoint defines a delegate to process requests and a collection of arbitrary metadata. 中繼資料可根據附加至每個端點的原則和組態,來實作跨領域關注。The metadata is used implement cross-cutting concerns based on policies and configuration attached to each endpoint.

路由系統具有下列特性:The routing system has the following characteristics:

  • 使用路由範本語法以 Token 化路由參數來定義路由。Route template syntax is used to define routes with tokenized route parameters.

  • 允許傳統式和屬性式端點組態。Conventional-style and attribute-style endpoint configuration is permitted.

  • IRouteConstraint 可用來判斷 URL 參數是否包含對指定端點條件約束有效的值。IRouteConstraint is used to determine whether a URL parameter contains a valid value for a given endpoint constraint.

  • 應用程式模型(例如 MVC/ Razor Pages)會註冊其所有端點,其具有可預測的路由案例執行。App models, such as MVC/Razor Pages, register all of their endpoints, which have a predictable implementation of routing scenarios.

  • 路由實作會在中介軟體管線需要時制定路由決策。The routing implementation makes routing decisions wherever desired in the middleware pipeline.

  • 在路由中介軟體之後出現的中介軟體可以檢查指定要求 URI 的路由中介軟體端點決策。Middleware that appears after a Routing Middleware can inspect the result of the Routing Middleware's endpoint decision for a given request URI.

  • 您可以針對中介軟體管線中任何位置的應用程式,列舉其中的所有端點。It's possible to enumerate all of the endpoints in the app anywhere in the middleware pipeline.

  • 應用程式可以根據端點資訊使用路由來產生 URL (例如,針對重新導向或連結),因此避免硬式編碼的 URL,這有助於可維護性。An app can use routing to generate URLs (for example, for redirection or links) based on endpoint information and thus avoid hard-coded URLs, which helps maintainability.

  • URL 是根據支援任意擴充性的位址所產生:URL generation is based on addresses, which support arbitrary extensibility:

注意

隨著 ASP.NET Core 2.2 中的端點路由發行,端點連結僅限於 MVC/ Razor pages 動作和頁面。With the release of endpoint routing in ASP.NET Core 2.2, endpoint linking is limited to MVC/Razor Pages actions and pages. 未來版本將規劃擴充端點連結功能。The expansions of endpoint-linking capabilities is planned for future releases.

路由會透過 RouterMiddleware 類別連線到中介軟體管線。Routing is connected to the middleware pipeline by the RouterMiddleware class. ASP.NET CORE mvc會將路由新增至中介軟體管線,作為其設定的一部分,並處理 MVC 和 Razor 頁面應用程式中的路由。ASP.NET Core MVC adds routing to the middleware pipeline as part of its configuration and handles routing in MVC and Razor Pages apps. 若要了解如何使用路由作為獨立元件,請參閱使用路由中介軟體一節。To learn how to use routing as a standalone component, see the Use Routing Middleware section.

URL 比對URL matching

URL 比對是路由用來將傳入要求分派給「端點」** 的處理序。URL matching is the process by which routing dispatches an incoming request to an endpoint. 這個處理序是基於 URL 路徑中的資料,但是可以擴展為考慮要求中的任何資料。This process is based on data in the URL path but can be extended to consider any data in the request. 分派要求給不同處理常式的能力,是調整應用程式大小和複雜度的關鍵。The ability to dispatch requests to separate handlers is key to scaling the size and complexity of an app.

端點路由中的路由系統負責制定所有分派決策。The routing system in endpoint routing is responsible for all dispatching decisions. 由於中介軟體會根據所選取的端點來套用原則,因此請務必在路由系統內制定可能影響分派或應用安全性原則的任何決策。Since the middleware applies policies based on the selected endpoint, it's important that any decision that can affect dispatching or the application of security policies is made inside the routing system.

執行端點委派時,會根據到目前為止所執行的要求處理,將 RouteContext.RouteData 的屬性設定為適當的值。When the endpoint delegate is executed, the properties of RouteContext.RouteData are set to appropriate values based on the request processing performed thus far.

RouteData.Values 是「路由值」** 的字典,而路由值產生自路由。RouteData.Values is a dictionary of route values produced from the route. 這些值通常是透過將 URL 語彙基元化來決定,可以用來接受使用者輸入,或在應用程式內做出進一步的分派決策。These values are usually determined by tokenizing the URL and can be used to accept user input or to make further dispatching decisions inside the app.

RouteData.DataTokens 是其他資料的屬性包,而這些資料與相符路由相關。RouteData.DataTokens is a property bag of additional data related to the matched route. 提供了 DataTokens 來支援與每個路由建立關聯的狀態資料,因此應用程式可以依據符合哪一個路由來制定決策。DataTokens are provided to support associating state data with each route so that the app can make decisions based on which route matched. 這些是開發人員定義的值,不會以任何方式影響路由的行為。These values are developer-defined and do not affect the behavior of routing in any way. 此外,儲藏在 RouteData.DataTokens 中的值可以是任何類型,對比之下,RouteData.Values 則必須可轉換成字串或可從字串轉換。Additionally, values stashed in RouteData.DataTokens can be of any type, in contrast to RouteData.Values, which must be convertible to and from strings.

RouteData.Routers 是成功符合要求的參與路由清單。RouteData.Routers is a list of the routes that took part in successfully matching the request. 路由可以用巢狀方式置於彼此內部。Routes can be nested inside of one another. Routers 屬性會透過導致產生相符項目的路由邏輯樹狀結構反映路徑。The Routers property reflects the path through the logical tree of routes that resulted in a match. 一般而言,Routers 中的第一個項目是路由集合,應該用於產生 URL。Generally, the first item in Routers is the route collection and should be used for URL generation. Routers 中的最後一個項目是相符的路由處理常式。The last item in Routers is the route handler that matched.

使用 LinkGenerator 產生 URLURL generation with LinkGenerator

URL 產生是路由可用來依據一組路由值建立 URL 路徑的處理序。URL generation is the process by which routing can create a URL path based on a set of route values. 這可讓您在端點和存取它們的 URL 之間建立邏輯分隔。This allows for a logical separation between your endpoints and the URLs that access them.

端點路由包含連結產生器 API (LinkGenerator)。Endpoint routing includes the Link Generator API (LinkGenerator). LinkGenerator是可從DI抓取的單一服務。LinkGenerator is a singleton service that can be retrieved from DI. 您可以在執行要求內容外部使用此 API。The API can be used outside of the context of an executing request. MVC 的 IUrlHelper 及依賴 IUrlHelper 的情節 (例如標籤協助程式、HTML 協助程式和動作結果) 均使用連結產生器來提供連結產生功能。MVC's IUrlHelper and scenarios that rely on IUrlHelper, such as Tag Helpers, HTML Helpers, and Action Results, use the link generator to provide link generating capabilities.

連結產生器背後支援的概念為「位址」** 和「位址配置」**。The link generator is backed by the concept of an address and address schemes. 位址配置可讓您判斷應考慮用於連結產生的端點。An address scheme is a way of determining the endpoints that should be considered for link generation. 例如,許多使用者熟悉的路由名稱和路由值案例, Razor 都是以位址配置的形式來執行。For example, the route name and route values scenarios many users are familiar with from MVC/Razor Pages are implemented as an address scheme.

連結產生器可以透過下列擴充方法連結至 MVC/ Razor pages 動作和頁面:The link generator can link to MVC/Razor Pages actions and pages via the following extension methods:

這些方法的多載接受包含 HttpContext 的引數。An overload of these methods accepts arguments that include the HttpContext. 這些方法的功能等同於 Url.ActionUrl.Page,但提供更多彈性和選項。These methods are functionally equivalent to Url.Action and Url.Page but offer additional flexibility and options.

GetPath* 方法與 Url.ActionUrl.Page 最類似,因為它們會產生包含絕對路徑的 URI。The GetPath* methods are most similar to Url.Action and Url.Page in that they generate a URI containing an absolute path. GetUri* 方法一律會產生包含配置和主機的絕對 URI。The GetUri* methods always generate an absolute URI containing a scheme and host. 接受 HttpContext 的方法會在執行要求的內容中產生 URI。The methods that accept an HttpContext generate a URI in the context of the executing request. 除非遭到覆寫,否則會使用來自執行要求的環境路由值、URL 基底路徑、配置和主機。The ambient route values, URL base path, scheme, and host from the executing request are used unless overridden.

呼叫 LinkGenerator 並指定一個位址。LinkGenerator is called with an address. 執行下列兩個步驟來產生 URI:Generating a URI occurs in two steps:

  1. 將位址繫結至符合該位址的端點清單。An address is bound to a list of endpoints that match the address.
  2. 評估每個端點的 RoutePattern,直到找到符合所提供值的路由模式。Each endpoint's RoutePattern is evaluated until a route pattern that matches the supplied values is found. 產生的輸出會與提供給連結產生器的其他 URI 組件合併並傳回。The resulting output is combined with the other URI parts supplied to the link generator and returned.

LinkGenerator 提供的方法支援適用於任何位址類型的標準連結產生功能。The methods provided by LinkGenerator support standard link generation capabilities for any type of address. 使用連結產生器的最便利方式是透過執行特定位址類型作業的擴充方法。The most convenient way to use the link generator is through extension methods that perform operations for a specific address type.

擴充方法Extension Method 描述Description
GetPathByAddress 根據提供的值產生具有絕對路徑的 URI。Generates a URI with an absolute path based on the provided values.
GetUriByAddress 根據提供的值產生絕對 URI。Generates an absolute URI based on the provided values.

警告

注意呼叫 LinkGenerator 方法的下列影響:Pay attention to the following implications of calling LinkGenerator methods:

  • 使用 GetUri* 擴充方法,並注意應用程式組態不會驗證傳入要求的 Host 標頭。Use GetUri* extension methods with caution in an app configuration that doesn't validate the Host header of incoming requests. 如果傳入要求的 Host 標頭未經驗證,則可能將未受信任的要求輸入傳回檢視/頁面 URI 中的用戶端。If the Host header of incoming requests isn't validated, untrusted request input can be sent back to the client in URIs in a view/page. 建議所有生產應用程式將其伺服器設定為驗證 Host 標頭是否為已知有效值。We recommend that all production apps configure their server to validate the Host header against known valid values.

  • 使用 LinkGenerator,並注意與 MapMapWhen 搭配使用的中介軟體。Use LinkGenerator with caution in middleware in combination with Map or MapWhen. Map* 會變更執行要求的基底路徑,這會影響連結產生的輸出。Map* changes the base path of the executing request, which affects the output of link generation. 所有的 LinkGenerator API 都允許指定基底路徑。All of the LinkGenerator APIs allow specifying a base path. 請一律指定空白基底路徑來恢復 Map* 對連結產生的影響。Always specify an empty base path to undo Map*'s affect on link generation.

與舊版路由的差異Differences from earlier versions of routing

ASP.NET Core 2.2 或更新版本中的端點路由與 ASP.NET Core 中的舊版路由之間有一些差異:A few differences exist between endpoint routing in ASP.NET Core 2.2 or later and earlier versions of routing in ASP.NET Core:

  • 端點路由系統不支援以 IRouter 為基礎的擴充性,包括從 Route 繼承。The endpoint routing system doesn't support IRouter-based extensibility, including inheriting from Route.

  • 端點路由不支援 WebApiCompatShimEndpoint routing doesn't support WebApiCompatShim. 使用 2.1相容性版本 (.SetCompatibilityVersion(CompatibilityVersion.Version_2_1)) 繼續使用相容性填充碼。Use the 2.1 compatibility version (.SetCompatibilityVersion(CompatibilityVersion.Version_2_1)) to continue using the compatibility shim.

  • 端點路由與使用傳統路由時所產生 URI 大小寫的行為不同。Endpoint Routing has different behavior for the casing of generated URIs when using conventional routes.

    請考慮下列預設路由範本:Consider the following default route template:

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

    假設您使用下列路由來產生動作連結:Suppose you generate a link to an action using the following route:

    var link = Url.Action("ReadPost", "blog", new { id = 17, });
    

    使用以 IRouter 為基礎的路由,此程式碼會產生 /blog/ReadPost/17 的 URI,其遵守所提供路由值的大小寫。With IRouter-based routing, this code generates a URI of /blog/ReadPost/17, which respects the casing of the provided route value. ASP.NET Core 2.2 或更新版本中的端點路由會產生 /Blog/ReadPost/17 ("Blog" 為大寫)。Endpoint routing in ASP.NET Core 2.2 or later produces /Blog/ReadPost/17 ("Blog" is capitalized). 端點路由提供 IOutboundParameterTransformer 介面,可用來全域自訂此行為,或為對應 URL 套用不同的慣例。Endpoint routing provides the IOutboundParameterTransformer interface that can be used to customize this behavior globally or to apply different conventions for mapping URLs.

    如需詳細資訊,請參閱參數轉換器參考一節。For more information, see the Parameter transformer reference section.

  • Razor當嘗試連結至不存在的控制器/動作或頁面時,MVC/Pages 搭配傳統路由使用的連結產生會有不同的行為。Link Generation used by MVC/Razor Pages with conventional routes behaves differently when attempting to link to an controller/action or page that doesn't exist.

    請考慮下列預設路由範本:Consider the following default route template:

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

    假設您使用預設範本和下列程式碼來產生動作連結:Suppose you generate a link to an action using the default template with the following:

    var link = Url.Action("ReadPost", "Blog", new { id = 17, });
    

    使用以 IRouter 為基礎的路由,結果一律為 /Blog/ReadPost/17,即使 BlogController 不存在或沒有 ReadPost 動作方法也一樣。With IRouter-based routing, the result is always /Blog/ReadPost/17, even if the BlogController doesn't exist or doesn't have a ReadPost action method. 如預期,如果動作方法存在,則 ASP.NET Core 2.2 或更新版本中的端點路由會產生 /Blog/ReadPost/17As expected, endpoint routing in ASP.NET Core 2.2 or later produces /Blog/ReadPost/17 if the action method exists. 不過,如果動作不存在,則端點路由會產生空字串。**However, endpoint routing produces an empty string if the action doesn't exist. 就概念而言,如果動作不存在,則端點路由不會假設端點存在。Conceptually, endpoint routing doesn't assume that the endpoint exists if the action doesn't exist.

  • 連結產生「環境值失效演算法」** 在搭配端點路由使用時會有不同的行為。The link generation ambient value invalidation algorithm behaves differently when used with endpoint routing.

    「環境值失效」** 是一種演算法,會從目前執行的要求 (環境值) 決定可用於連結產生作業的路由值。Ambient value invalidation is the algorithm that decides which route values from the currently executing request (the ambient values) can be used in link generation operations. 傳統路由一律會在連結至其他動作時,使額外的路由值失效。Conventional routing always invalidated extra route values when linking to a different action. 在 ASP.NET Core 2.2 版以前,屬性路由沒有此行為。Attribute routing didn't have this behavior prior to the release of ASP.NET Core 2.2. 在舊版的 ASP.NET Core 中,連結至使用相同路由參數名稱的其他動作會導致連結產生錯誤。In earlier versions of ASP.NET Core, links to another action that use the same route parameter names resulted in link generation errors. 在 ASP.NET Core 2.2 或更新版本中,這兩種路由形式都會在連結至其他動作時使值失效。In ASP.NET Core 2.2 or later, both forms of routing invalidate values when linking to another action.

    請考慮 ASP.NET Core 2.1 或更舊版本中的下列範例。Consider the following example in ASP.NET Core 2.1 or earlier. 連結至其他動作 (或其他頁面) 時,路由值可能會不適當地重複使用。When linking to another action (or another page), route values can be reused in undesirable ways.

    /Pages/Store/Product.cshtml 中:In /Pages/Store/Product.cshtml:

    @page "{id}"
    @Url.Page("/Login")
    

    /Pages/Login.cshtml 中:In /Pages/Login.cshtml:

    @page "{id?}"
    

    如果 URI 在 ASP.NET Core 2.1 或更舊版本中為 /Store/Product/18,則 @Url.Page("/Login") 在 Store/Info 頁面中產生的連結為 /Login/18If the URI is /Store/Product/18 in ASP.NET Core 2.1 or earlier, the link generated on the Store/Info page by @Url.Page("/Login") is /Login/18. 這會重複使用 id 值 18,即使連結目的地是完全不同的應用程式組件也一樣。The id value of 18 is reused, even though the link destination is different part of the app entirely. /Login 頁面內容中的 id 路由值可能是使用者識別碼值,而不是市集產品識別碼值。The id route value in the context of the /Login page is probably a user ID value, not a store product ID value.

    在 ASP.NET Core 2.2 或更新版本中的端點路由中,結果為 /LoginIn endpoint routing with ASP.NET Core 2.2 or later, the result is /Login. 當連結的目的地是不同的動作或頁面時,不會重複使用環境值。Ambient values aren't reused when the linked destination is a different action or page.

  • 往返路由參數語法:使用雙星號 (**) catch-all 參數語法時,斜線不會經過編碼。Round-tripping route parameter syntax: Forward slashes aren't encoded when using a double-asterisk (**) catch-all parameter syntax.

    在連結產生期間,除了斜線,路由系統還會對雙星號 (**) catch-all 參數 (例如 {**myparametername}) 中擷取的值進行編碼。During link generation, the routing system encodes the value captured in a double-asterisk (**) catch-all parameter (for example, {**myparametername}) except the forward slashes. ASP.NET Core 2.2 或更新版本中以 IRouter 為基礎的路由支援雙星號 catch-all。The double-asterisk catch-all is supported with IRouter-based routing in ASP.NET Core 2.2 or later.

    舊版 ASP.NET Core 中的單一星號 catch-all ({*myparametername}) 參數語法仍會受到支援,而且斜線會經過編碼。The single asterisk catch-all parameter syntax in prior versions of ASP.NET Core ({*myparametername}) remains supported, and forward slashes are encoded.

    路由Route 以下列項目產生的連結:Link generated with
    Url.Action(new { category = "admin/products" })
    /search/{*page} /search/admin%2Fproducts (斜線會經過編碼)/search/admin%2Fproducts (the forward slash is encoded)
    /search/{**page} /search/admin/products

中介軟體範例Middleware example

在下列範例中,中介軟體使用 LinkGenerator API 建立列出市集產品的動作方法連結。In the following example, a middleware uses the LinkGenerator API to create link to an action method that lists store products. 應用程式中的任何類別都可以使用連結產生器,方法是將它插入類別並呼叫 GenerateLinkUsing the link generator by injecting it into a class and calling GenerateLink is available to any class in an app.

using Microsoft.AspNetCore.Routing;

public class ProductsLinkMiddleware
{
    private readonly LinkGenerator _linkGenerator;

    public ProductsLinkMiddleware(RequestDelegate next, LinkGenerator linkGenerator)
    {
        _linkGenerator = linkGenerator;
    }

    public async Task InvokeAsync(HttpContext httpContext)
    {
        var url = _linkGenerator.GetPathByAction("ListProducts", "Store");

        httpContext.Response.ContentType = "text/plain";

        await httpContext.Response.WriteAsync($"Go to {url} to see our products.");
    }
}

建立路由Create routes

大部分的應用程式會藉由呼叫 MapRoute 或其中一個 IRouteBuilder 上定義的類似擴充方法來定建立路由。Most apps create routes by calling MapRoute or one of the similar extension methods defined on IRouteBuilder. 任何 IRouteBuilder 擴充方法都會建立 Route 的執行個體,並將它新增至路由集合。Any of the IRouteBuilder extension methods create an instance of Route and add it to the route collection.

MapRoute 不接受路由處理常式參數。MapRoute doesn't accept a route handler parameter. MapRoute 只會新增 DefaultHandler 所處理的路由。MapRoute only adds routes that are handled by the DefaultHandler. 若要深入了解 MVC 中的路由功能,請參閱 ASP.NET Core 中的路由至控制器動作To learn more about routing in MVC, see ASP.NET Core 中的路由至控制器動作.

下列程式碼範例是典型 ASP.NET Core MVC 路由定義所使用的 MapRoute 呼叫範例:The following code example is an example of a MapRoute call used by a typical ASP.NET Core MVC route definition:

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

此範本會比對 URL 路徑,並擷取路由值。This template matches a URL path and extracts the route values. 例如,路徑 /Products/Details/17 會產生下列路由值:{ controller = Products, action = Details, id = 17 }For example, the path /Products/Details/17 generates the following route values: { controller = Products, action = Details, id = 17 }.

路由值是透過將 URL 路徑分割成區段,並比對每個區段與路由範本中的「路由參數」** 名稱來判定。Route values are determined by splitting the URL path into segments and matching each segment with the route parameter name in the route template. 路由參數為具名。Route parameters are named. 參數是透過以括弧 { ... } 括住參數名稱來定義。The parameters defined by enclosing the parameter name in braces { ... }.

上述範本也可以比對 URL 路徑 / 並產生值 { controller = Home, action = Index }The preceding template could also match the URL path / and produce the values { controller = Home, action = Index }. 發生這種情況是因為 {controller}{action} 路由參數有預設值,而 id 路由參數為選擇性參數。This occurs because the {controller} and {action} route parameters have default values and the id route parameter is optional. 路由參數名稱之後緊接著值的等號 (=) 會定義參數預設值。An equals sign (=) followed by a value after the route parameter name defines a default value for the parameter. 路由參數名稱之後的問號 (?) 會定義選擇性參數。A question mark (?) after the route parameter name defines an optional parameter.

在路由相符時,具有預設值的路由參數一定** 會產生路由值。Route parameters with a default value always produce a route value when the route matches. 如果沒有對應的 URL 路徑區段,選擇性參數不會產生路由值。Optional parameters don't produce a route value if there is no corresponding URL path segment. 如需路由範本情節和語法的詳細描述,請參閱路由範本參考一節。See the Route template reference section for a thorough description of route template scenarios and syntax.

在下列範例中,路由參數定義 {id:int} 會定義 id 路由參數的路由條件約束In the following example, the route parameter definition {id:int} defines a route constraint for the id route parameter:

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

此範本會符合 /Products/Details/17 等 URL 路徑,但不符合 /Products/Details/ApplesThis template matches a URL path like /Products/Details/17 but not /Products/Details/Apples. 路由條件約束會實作 IRouteConstraint,並檢查路由值以進行驗證。Route constraints implement IRouteConstraint and inspect route values to verify them. 在此範例中,路由值 id 必須可以轉換為整數。In this example, the route value id must be convertible to an integer. 如需架構所提供之路由條件約束的說明,請參閱路由條件約束參考See route-constraint-reference for an explanation of route constraints provided by the framework.

MapRoute 的其他多載接受 constraintsdataTokensdefaults 的值。Additional overloads of MapRoute accept values for constraints, dataTokens, and defaults. 這些參數通常是用來傳遞匿名類型的物件,其中匿名類型的屬性名稱符合路由參數名稱。The typical usage of these parameters is to pass an anonymously typed object, where the property names of the anonymous type match route parameter names.

下列 MapRoute 範例會建立對等的路由:The following MapRoute examples create equivalent routes:

routes.MapRoute(
    name: "default_route",
    template: "{controller}/{action}/{id?}",
    defaults: new { controller = "Home", action = "Index" });

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

提示

對於簡單的路由而言,定義條件約束和預設的內嵌語法可能很方便。The inline syntax for defining constraints and defaults can be convenient for simple routes. 不過,內嵌語法不支援某些情節 (例如資料語彙基元)。However, there are scenarios, such as data tokens, that aren't supported by inline syntax.

下列範例將示範一些其他情節:The following example demonstrates a few additional scenarios:

routes.MapRoute(
    name: "blog",
    template: "Blog/{**article}",
    defaults: new { controller = "Blog", action = "ReadArticle" });

上述範本會比對 /Blog/All-About-Routing/Introduction 等 URL 路徑,並擷取值 { controller = Blog, action = ReadArticle, article = All-About-Routing/Introduction }The preceding template matches a URL path like /Blog/All-About-Routing/Introduction and extracts the values { controller = Blog, action = ReadArticle, article = All-About-Routing/Introduction }. 即使範本中沒有任何對應的路由參數,路由也會產生 controlleraction 的預設路由值。The default route values for controller and action are produced by the route even though there are no corresponding route parameters in the template. 預設值可以在路由範本中指定。Default values can be specified in the route template. article 路由參數透過在路由參數名稱之前加上雙星號 (**) 來定義為 catch-allThe article route parameter is defined as a catch-all by the appearance of an double asterisk (**) before the route parameter name. 全部擷取路由參數會擷取 URL 路徑的其餘部分,而且也可以符合空字串。Catch-all route parameters capture the remainder of the URL path and can also match the empty string.

下列範例會新增路由條件約束和資料語彙基元:The following example adds route constraints and data tokens:

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" });

上述範本會比對 /en-US/Products/5 等 URL 路徑,並擷取值 { controller = Products, action = Details, id = 5 } 和資料語彙基元 { locale = en-US }The preceding template matches a URL path like /en-US/Products/5 and extracts the values { controller = Products, action = Details, id = 5 } and the data tokens { locale = en-US }.

[區域變數] 視窗語彙基元

路由類別 URL 產生Route class URL generation

Route 類別也可以結合一組路由值與其路由範本來產生 URL。The Route class can also perform URL generation by combining a set of route values with its route template. 這在邏輯上是比對 URL 路徑的反向處理序。This is logically the reverse process of matching the URL path.

提示

若要進一步了解 URL 產生,請假設您想要產生的 URL,並考慮路由範本將會如何比對該 URL。To better understand URL generation, imagine what URL you want to generate and then think about how a route template would match that URL. 產生的值為何?What values would be produced? 這與 URL 產生在 Route 類別中的運作方式大致相同。This is the rough equivalent of how URL generation works in the Route class.

下列範例使用一般 ASP.NET Core MVC 預設路由:The following example uses a general ASP.NET Core MVC default route:

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

路由值為 { controller = Products, action = List } 時,會產生 URL /Products/ListWith the route values { controller = Products, action = List }, the URL /Products/List is generated. 路由值會取代對應的路由參數,以形成 URL 路徑。The route values are substituted for the corresponding route parameters to form the URL path. 由於 id 是選擇性路由參數,因此沒有 id 值也可以成功產生 URL。Since id is an optional route parameter, the URL is successfully generated without a value for id.

路由值為 { controller = Home, action = Index } 時,會產生 URL /With the route values { controller = Home, action = Index }, the URL / is generated. 所提供的路由值符合預設值,因此可以放心地省略這些預設值對應的區段。The provided route values match the default values, and the segments corresponding to the default values are safely omitted.

這兩個產生的 URL 會使用下列路由定義 (/Home/Index/) 反覆存取,並產生用來產生 URL 的相同路由值。Both URLs generated round-trip with the following route definition (/Home/Index and /) produce the same route values that were used to generate the URL.

注意

使用 ASP.NET Core MVC 的應用程式應該使用 UrlHelper 來產生 URL,而不是直接呼叫路由。An app using ASP.NET Core MVC should use UrlHelper to generate URLs instead of calling into routing directly.

如需 URL 產生的詳細資訊,請參閱 URI 產生參考一節。For more information on URL generation, see the Url generation reference section.

使用路由中介軟體Use Routing Middleware

參考應用程式專案檔中的 Microsoft.AspNetCore.App 中繼套件Reference the Microsoft.AspNetCore.App metapackage in the app's project file.

Startup.ConfigureServices 中,將路由新增至服務容器:Add routing to the service container in Startup.ConfigureServices:

public void ConfigureServices(IServiceCollection services)
{
    services.AddRouting();
}

路由必須設定在 Startup.Configure 方法中。Routes must be configured in the Startup.Configure method. 範例應用程式使用下列 API:The sample app uses the following APIs:

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);

下表顯示使用指定 URL 的回應。The following table shows the responses with the given URIs.

URIURI 回應Response
/package/create/3 Hello!Hello! Route values: [operation, create], [id, 3]Route values: [operation, create], [id, 3]
/package/track/-3 Hello!Hello! Route values: [operation, track], [id, -3]Route values: [operation, track], [id, -3]
/package/track/-3/ Hello!Hello! Route values: [operation, track], [id, -3]Route values: [operation, track], [id, -3]
/package/track/ 要求失敗,沒有相符項目。The request falls through, no match.
GET /hello/Joe Hi, Joe!Hi, Joe!
POST /hello/Joe 要求失敗,僅符合 HTTP GET。The request falls through, matches HTTP GET only.
GET /hello/Joe/Smith 要求失敗,沒有相符項目。The request falls through, no match.

架構會提供一組擴充方法來建立路由 (RequestDelegateRouteBuilderExtensions):The framework provides a set of extension methods for creating routes (RequestDelegateRouteBuilderExtensions):

Map[Verb] 方法會使用條件約束,將路由限制為方法名稱中的 HTTP 指令動詞。The Map[Verb] methods use constraints to limit the route to the HTTP Verb in the method name. 如需範例,請參閱 MapGetMapVerbFor example, see MapGet and MapVerb.

路由範本參考Route template reference

大括弧 ({ ... }) 內的語彙基元定義路由相符時會繫結的「路由參數」**。Tokens within curly braces ({ ... }) define route parameters that are bound if the route is matched. 您可以在路由區段中定義多個路由參數,但其必須以常值分隔。You can define more than one route parameter in a route segment, but they must be separated by a literal value. 例如,{controller=Home}{action=Index} 不是有效的路由,因為 {controller}{action} 之間沒有任何常值。For example, {controller=Home}{action=Index} isn't a valid route, since there's no literal value between {controller} and {action}. 這些路由參數必須有一個名稱,並且可以指定其他屬性。These route parameters must have a name and may have additional attributes specified.

路由參數之外的常值文字 (例如,{id}) 和路徑分隔符號 / 必須符合 URL 中的文字。Literal text other than route parameters (for example, {id}) and the path separator / must match the text in the URL. 文字比對會區分大小寫,並以 URL 路徑的已解碼表示法為基礎。Text matching is case-insensitive and based on the decoded representation of the URLs path. 若要比對常值路由參數分隔符號 ({}),請重複字元 ({{}}) 來將分隔符號逸出。To match a literal route parameter delimiter ({ or }), escape the delimiter by repeating the character ({{ or }}).

URL 模式嘗試擷取具有選擇性副檔名的檔案名稱時,具有其他考量。URL patterns that attempt to capture a file name with an optional file extension have additional considerations. 以範本 files/{filename}.{ext?} 為例。For example, consider the template files/{filename}.{ext?}. filenameext 都存在值時,就會填入這兩個值。When values for both filename and ext exist, both values are populated. 如果 URL 中只有 filename 存在值,由於結尾的句點 (.) 是選擇性項目,因此路由相符。If only a value for filename exists in the URL, the route matches because the trailing period (.) is optional. 下列 URL 符合此路由:The following URLs match this route:

  • /files/myFile.txt
  • /files/myFile

您可以使用一個星號 (*) 或雙星號 (**) 作為路由參數的前置詞,以繫結至 URI 的其餘部分。You can use an asterisk (*) or double asterisk (**) as a prefix to a route parameter to bind to the rest of the URI. 這稱為 catch-all 參數。These are called a catch-all parameters. 例如,blog/{**slug} 符合以 /blog 開頭且其後有任何值 (這會指派給 slug 路由值) 的所有 URI。For example, blog/{**slug} matches any URI that starts with /blog and has any value following it, which is assigned to the slug route value. 全部擷取參數也可以符合空字串。Catch-all parameters can also match the empty string.

當使用路由產生 URL (包括路徑分隔符號 (/) 字元) 時,catch-all 參數會逸出適當的字元。The catch-all parameter escapes the appropriate characters when the route is used to generate a URL, including path separator (/) characters. 例如,路由值為 { path = "my/path" } 的路由 foo/{*path} 會產生 foo/my%2FpathFor example, the route foo/{*path} with route values { path = "my/path" } generates foo/my%2Fpath. 請注意逸出的斜線。Note the escaped forward slash. 若要反覆存取路徑分隔符號字元,請使用 ** 路由參數前置詞。To round-trip path separator characters, use the ** route parameter prefix. 具有 { path = "my/path" } 的路由 foo/{**path} 會產生 foo/my/pathThe route foo/{**path} with { path = "my/path" } generates foo/my/path.

路由參數可能有「預設值」**,指定方法是在參數名稱之後指定預設值,並以等號 (=) 分隔。Route parameters may have default values designated by specifying the default value after the parameter name separated by an equals sign (=). 例如,{controller=Home} 定義 Home 作為 controller 的預設值。For example, {controller=Home} defines Home as the default value for controller. 如果 URL 中沒有用於參數的任何值,則會使用預設值。The default value is used if no value is present in the URL for the parameter. 路由參數也可以設為選擇性,方法是在參數名稱結尾附加問號 (?),如 id? 中所示。Route parameters are made optional by appending a question mark (?) to the end of the parameter name, as in id?. 選擇性值與預設路由參數之間的差異在於,具有預設值的路由參數一定會產生值—選擇性參數只有在要求 URL 提供值時才會有值。The difference between optional values and default route parameters is that a route parameter with a default value always produces a value—an optional parameter has a value only when a value is provided by the request URL.

路由參數可能具有條件約束,這些條件約束必須符合與 URL 繫結的路由值。Route parameters may have constraints that must match the route value bound from the URL. 在路由參數名稱之後新增分號 (:) 和條件約束名稱,即可指定路由參數的「內嵌條件約束」**。Adding a colon (:) and constraint name after the route parameter name specifies an inline constraint on a route parameter. 如果條件約束需要引數,這些引數會在條件約束名稱後面以括弧 ((...)) 括住。If the constraint requires arguments, they're enclosed in parentheses ((...)) after the constraint name. 指定多個內嵌條件約束的方法是附加另一個冒號 (:) 和條件約束名稱。Multiple inline constraints can be specified by appending another colon (:) and constraint name.

條件約束名稱和引述會傳遞至 IInlineConstraintResolver 服務來建立 IRouteConstraint 的執行個體,以用於 URL 處理。The constraint name and arguments are passed to the IInlineConstraintResolver service to create an instance of IRouteConstraint to use in URL processing. 例如,路由範本 blog/{article:minlength(10)} 指定具有引數 10minlength 條件約束。For example, the route template blog/{article:minlength(10)} specifies a minlength constraint with the argument 10. 如需路由條件約束詳細資訊和架構所提供的條件約束清單,請參閱路由條件約束參考一節。For more information on route constraints and a list of the constraints provided by the framework, see the Route constraint reference section.

路由參數也可以具有參數轉換器,以在產生連結及根據 URL 比對動作和頁面時,轉換參數的值。Route parameters may also have parameter transformers, which transform a parameter's value when generating links and matching actions and pages to URLs. 與條件約束類似,可以透過在路徑參數名稱後面新增冒號 (:) 和轉換器名稱,將參數轉換器內嵌新增至路徑參數。Like constraints, parameter transformers can be added inline to a route parameter by adding a colon (:) and transformer name after the route parameter name. 例如,路由範本 blog/{article:slugify} 會指定 slugify 轉換器。For example, the route template blog/{article:slugify} specifies a slugify transformer. 如需參數轉換器的詳細資訊,請參閱參數轉器參考一節。For more information on parameter transformers, see the Parameter transformer reference section.

下表示範範例路由範本及其行為。The following table demonstrates example route templates and their behavior.

路由範本Route Template 範例比對 URIExample Matching URI 要求 URI…The request URI…
hello /hello 只比對單一路徑 /helloOnly matches the single path /hello.
{Page=Home} / 比對並將 Page 設定為 HomeMatches and sets Page to Home.
{Page=Home} /Contact 比對並將 Page 設定為 ContactMatches and sets Page to Contact.
{controller}/{action}/{id?} /Products/List 對應至 Products 控制器和 List 動作。Maps to the Products controller and List action.
{controller}/{action}/{id?} /Products/Details/123 對應至 Products 控制器和 Details 動作 (id 設定為 123)。Maps to the Products controller and Details action (id set to 123).
{controller=Home}/{action=Index}/{id?} / 對應至 Home 控制器和 Index 方法 (會忽略 id)。Maps to the Home controller and Index method (id is ignored).

使用範本通常是最簡單的路由方式。Using a template is generally the simplest approach to routing. 條件約束和預設值也可以在路由範本外部指定。Constraints and defaults can also be specified outside the route template.

提示

啟用記錄以查看內建路由實作 (例如 Route) 如何符合要求。Enable Logging to see how the built-in routing implementations, such as Route, match requests.

保留的路由名稱Reserved routing names

下列關鍵字是保留的名稱,不能用作路由名稱或參數:The following keywords are reserved names and can't be used as route names or parameters:

  • action
  • area
  • controller
  • handler
  • page

路由條件約束參考Route constraint reference

路由條件約束執行時機是出現符合傳入 URL 的項目,並將 URL 路徑語彙基元化成路由值時。Route constraints execute when a match has occurred to the incoming URL and the URL path is tokenized into route values. 路由條件約束通常會透過路由範本檢查相關聯的路由值,並對是否可接受值做出是/否決策。Route constraints generally inspect the route value associated via the route template and make a yes/no decision about whether or not the value is acceptable. 某些路由條件約束會使用路由值以外的資料,以考慮是否可以路由要求。Some route constraints use data outside the route value to consider whether the request can be routed. 例如,HttpMethodRouteConstraint 可以依據其 HTTP 指令動詞接受或拒絕要求。For example, the HttpMethodRouteConstraint can accept or reject a request based on its HTTP verb. 條件約束可用於路由要求和連結產生。Constraints are used in routing requests and link generation.

警告

請勿針對輸入驗證使用條件約束。Don't use constraints for input validation. 如果針對輸入驗證使用條件約束,則無效的輸入會導致產生「404 - 找不到」** 回應,而不是「400 - 錯誤要求」** 與適當的錯誤訊息。If constraints are used for input validation, invalid input results in a 404 - Not Found response instead of a 400 - Bad Request with an appropriate error message. 路由條件約束會用來釐清類似的路由,而不是用來驗證特定路由的輸入。Route constraints are used to disambiguate similar routes, not to validate the inputs for a particular route.

下表示範範例路由條件約束及其預期行為。The following table demonstrates example route constraints and their expected behavior.

條件約束Constraint 範例Example 範例相符項目Example matches 附註Notes
int {id:int} 123456789, -123456789123456789, -123456789 符合任何整數。Matches any integer.
bool {active:bool} true, FALSEtrue, FALSE 符合 truefalseMatches true or false. 不區分大小寫。Case-insensitive.
datetime {dob:datetime} 2016-12-31, 2016-12-31 7:32pm2016-12-31, 2016-12-31 7:32pm 符合不因文化特性而異的有效 DateTime 值。Matches a valid DateTime value in the invariant culture. 請參閱先前的警告。See preceding warning.
decimal {price:decimal} 49.99, -1,000.0149.99, -1,000.01 符合不因文化特性而異的有效 decimal 值。Matches a valid decimal value in the invariant culture. 請參閱先前的警告。See preceding warning.
double {weight:double} 1.234, -1,001.01e81.234, -1,001.01e8 符合不因文化特性而異的有效 double 值。Matches a valid double value in the invariant culture. 請參閱先前的警告。See preceding warning.
float {weight:float} 1.234, -1,001.01e81.234, -1,001.01e8 符合不因文化特性而異的有效 float 值。Matches a valid float value in the invariant culture. 請參閱先前的警告。See preceding warning.
guid {id:guid} CD2C1638-1638-72D5-1638-DEADBEEF1638, {CD2C1638-1638-72D5-1638-DEADBEEF1638}CD2C1638-1638-72D5-1638-DEADBEEF1638, {CD2C1638-1638-72D5-1638-DEADBEEF1638} 符合有效的 Guid 值。Matches a valid Guid value.
long {ticks:long} 123456789, -123456789123456789, -123456789 符合有效的 long 值。Matches a valid long value.
minlength(value) {username:minlength(4)} Rick 字串必須至少有4個字元。String must be at least 4 characters.
maxlength(value) {filename:maxlength(8)} MyFile 字串最多可以有8個字元。String has maximum of 8 characters.
length(length) {filename:length(12)} somefile.txt 字串長度必須剛好12個字元。String must be exactly 12 characters long.
length(min,max) {filename:length(8,16)} somefile.txt 字串必須至少為8個字元,且最多可以有16個字元。String must be at least 8 and has maximum of 16 characters.
min(value) {age:min(18)} 19 整數值必須至少為18。Integer value must be at least 18.
max(value) {age:max(120)} 91 整數值上限為120。Integer value maximum of 120.
range(min,max) {age:range(18,120)} 91 整數值必須至少為18,而最大值為120。Integer value must be at least 18 and maximum of 120.
alpha {name:alpha} Rick 字串必須包含一或多個字母字元 a - zString must consist of one or more alphabetical characters a-z. 不區分大小寫。Case-insensitive.
regex(expression) {ssn:regex(^\\d{{3}}-\\d{{2}}-\\d{{4}}$)} 123-45-6789 字串必須符合正則運算式。String must match the regular expression. 請參閱定義正則運算式的秘訣。See tips about defining a regular expression.
required {name:required} Rick 用來強制在 URL 產生期間出現非參數值。Used to enforce that a non-parameter value is present during URL generation.

以冒號分隔的多個條件約束,可以套用至單一參數。Multiple, colon-delimited constraints can be applied to a single parameter. 例如,下列條件約束會將參數限制在 1 或更大的整數值:For example, the following constraint restricts a parameter to an integer value of 1 or greater:

[Route("users/{id:int:min(1)}")]
public User GetUserById(int id) { }

警告

確認 URL 可以轉換成 CLR 類型的路由條件約束 (例如 intDateTime) 一律使用不因國別而異的文化特性。Route constraints that verify the URL and are converted to a CLR type (such as int or DateTime) always use the invariant culture. 這些條件約束假設 URL 不可當地語系化。These constraints assume that the URL is non-localizable. 架構提供的路由條件約束不會修改路由值中儲存的值。The framework-provided route constraints don't modify the values stored in route values. 所有從 URL 剖析而來的路由值會儲存為字串。All route values parsed from the URL are stored as strings. 例如,float 條件約束會嘗試將路由值轉換成浮點數,但轉換的值只能用來確認它可以轉換成浮點數。For example, the float constraint attempts to convert the route value to a float, but the converted value is used only to verify it can be converted to a float.

規則運算式Regular expressions

ASP.NET Core 架構將 RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvariant 新增至規則運算式建構函式。The ASP.NET Core framework adds RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvariant to the regular expression constructor. 如需這些成員的說明,請參閱 RegexOptionsSee RegexOptions for a description of these members.

正則運算式會使用類似路由和 c # 語言所使用的分隔符號和標記。Regular expressions use delimiters and tokens similar to those used by routing and the C# language. 規則運算式的語彙基元必須逸出。Regular expression tokens must be escaped. 若要在路由中使用正則運算式 ^\d{3}-\d{2}-\d{4}$To use the regular expression ^\d{3}-\d{2}-\d{4}$ in routing:

  • 運算式必須在字串中提供單一反斜線 \ 字元,做為原始程式碼中的雙反斜線 \\ 字元。The expression must have the single backslash \ characters provided in the string as double backslash \\ characters in the source code.
  • 正則運算式必須是, \\ 才能將 \ 字串 escape 字元轉義。The regular expression must us \\ in order to escape the \ string escape character.
  • \\使用逐字字串常值時,不需要正則運算式。The regular expression doesn't require \\ when using verbatim string literals.

若要 escape 路由參數分隔符號 {}[ 、,請將 ] 運算式中的字元、、、加倍 {{ } [[ ]]To escape routing parameter delimiter characters {, }, [, ], double the characters in the expression {{, }, [[, ]]. 下表顯示正則運算式和已轉義的版本:The following table shows a regular expression and the escaped version:

規則運算式Regular Expression 逸出的規則運算式Escaped Regular Expression
^\d{3}-\d{2}-\d{4}$ ^\\d{{3}}-\\d{{2}}-\\d{{4}}$
^[a-z]{2}$ ^[[a-z]]{{2}}$

路由中使用的正則運算式通常會以插入 ^ 號字元開頭,並比對字串的開始位置。Regular expressions used in routing often start with the caret ^ character and match starting position of the string. 這些運算式通常會以貨幣符號 $ 字元結尾,並比對字串的結尾。The expressions often end with the dollar sign $ character and match end of the string. ^$ 字元可確保規則運算式符合整個路由參數值。The ^ and $ characters ensure that the regular expression match the entire route parameter value. 若不使用 ^$ 字元,規則運算式會比對字串內的所有部分字串,這通常不是您想要的結果。Without the ^ and $ characters, the regular expression match any substring within the string, which is often undesirable. 下表提供範例,並說明它們符合或無法符合的原因。The following table provides examples and explains why they match or fail to match.

運算式Expression StringString 比對Match 註解Comment
[a-z]{2} hellohello Yes 子字串相符項目Substring matches
[a-z]{2} 123abc456123abc456 Yes 子字串相符項目Substring matches
[a-z]{2} mzmz Yes 符合運算式Matches expression
[a-z]{2} MZMZ Yes 不區分大小寫Not case sensitive
^[a-z]{2}$ hellohello No 請參閱上述的 ^$See ^ and $ above
^[a-z]{2}$ 123abc456123abc456 No 請參閱上述的 ^$See ^ and $ above

如需規則運算式語法的詳細資訊,請參閱 .NET Framework 規則運算式For more information on regular expression syntax, see .NET Framework Regular Expressions.

若要將參數限制為一組已知的可能值,請使用規則運算式。To constrain a parameter to a known set of possible values, use a regular expression. 例如,{action:regex(^(list|get|create)$)} 只會將 action 路由值與 listgetcreate 相符。For example, {action:regex(^(list|get|create)$)} only matches the action route value to list, get, or create. 如果已傳入條件約束字典,字串 ^(list|get|create)$ 則是對等項目。If passed into the constraints dictionary, the string ^(list|get|create)$ is equivalent. 已傳入條件約束字典 (未內嵌在範本內) 的條件約束,即使不符合其中一個已知的條件約束,也會被視為規則運算式。Constraints that are passed in the constraints dictionary (not inline within a template) that don't match one of the known constraints are also treated as regular expressions.

自訂路由條件約束Custom route constraints

除了內建的路由限制式之外,自訂路由限制式也可以透過實作 IRouteConstraint 介面來建立。In addition to the built-in route constraints, custom route constraints can be created by implementing the IRouteConstraint interface. IRouteConstraint 介面包含單一方法 Match,此方法會在滿足限制式時傳回 true,否則會傳回 falseThe IRouteConstraint interface contains a single method, Match, which returns true if the constraint is satisfied and false otherwise.

若要使用自訂 IRouteConstraint,路由限制式型別必須必須向應用程式的 ConstraintMap (在應用程式的服務容器中) 註冊。To use a custom IRouteConstraint, the route constraint type must be registered with the app's ConstraintMap in the app's service container. ConstraintMap 是一個目錄,它將路由限制式機碼對應到可驗證那些限制式的 IRouteConstraint 實作。A ConstraintMap is a dictionary that maps route constraint keys to IRouteConstraint implementations that validate those constraints. 更新應用程式的 ConstraintMap 時,可在 Startup.ConfigureServices 中於進行 services.AddRouting 呼叫時更新,或透過使用 services.Configure<RouteOptions> 直接設定 RouteOptions 來更新。An app's ConstraintMap can be updated in Startup.ConfigureServices either as part of a services.AddRouting call or by configuring RouteOptions directly with services.Configure<RouteOptions>. 例如:For example:

services.AddRouting(options =>
{
    options.ConstraintMap.Add("customName", typeof(MyCustomConstraint));
});

限制式接著能以一般方式套用到路由 (使用註冊限制式型別時使用名稱)。The constraint can then be applied to routes in the usual manner, using the name specified when registering the constraint type. 例如:For example:

[HttpGet("{id:customName}")]
public ActionResult<string> Get(string id)

參數轉換器參考Parameter transformer reference

參數轉換程式:Parameter transformers:

  • 會在為 Route 產生連結時執行。Execute when generating a link for a Route.
  • 實作 Microsoft.AspNetCore.Routing.IOutboundParameterTransformerImplement Microsoft.AspNetCore.Routing.IOutboundParameterTransformer.
  • 是使用 ConstraintMap 進行設定的。Are configured using ConstraintMap.
  • 採用參數的路由值,並將它轉換為新的字串值。Take the parameter's route value and transform it to a new string value.
  • 導致在所產生連結中使用已轉換的值。Result in using the transformed value in the generated link.

例如,具有 Url.Action(new { article = "MyTestArticle" }) 之路由模式 blog\{article:slugify} 中的自訂 slugify 參數轉換器,會產生 blog\my-test-articleFor example, a custom slugify parameter transformer in route pattern blog\{article:slugify} with Url.Action(new { article = "MyTestArticle" }) generates blog\my-test-article.

若要在路由模式中使用參數轉換器,請先在 Startup.ConfigureServices 中使用 ConstraintMap 進行設定:To use a parameter transformer in a route pattern, configure it first using ConstraintMap in Startup.ConfigureServices:

services.AddRouting(options =>
{
    // Replace the type and the name used to refer to it with your own
    // IOutboundParameterTransformer implementation
    options.ConstraintMap["slugify"] = typeof(SlugifyParameterTransformer);
});

架構會使用參數轉換器來轉換端點解析的 URI。Parameter transformers are used by the framework to transform the URI where an endpoint resolves. 例如,ASP.NET Core MVC 會使用參數轉換器,轉換用於比對 areacontrolleractionpage 的路由值。For example, ASP.NET Core MVC uses parameter transformers to transform the route value used to match an area, controller, action, and page.

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

使用上述的路由,動作 SubscriptionManagementController.GetAll 會與URI /subscription-management/get-all 比對。With the preceding route, the action SubscriptionManagementController.GetAll is matched with the URI /subscription-management/get-all. 參數轉換器不會變更用來產生連結的路由值。A parameter transformer doesn't change the route values used to generate a link. 例如,Url.Action("GetAll", "SubscriptionManagement") 會輸出 /subscription-management/get-allFor example, Url.Action("GetAll", "SubscriptionManagement") outputs /subscription-management/get-all.

ASP.NET Core 針對搭配產生的路由使用參數轉換程式提供了 API 慣例:ASP.NET Core provides API conventions for using a parameter transformers with generated routes:

  • ASP.NET Core MVC 有 Microsoft.AspNetCore.Mvc.ApplicationModels.RouteTokenTransformerConvention API 慣例。ASP.NET Core MVC has the Microsoft.AspNetCore.Mvc.ApplicationModels.RouteTokenTransformerConvention API convention. 此慣例會將所指定參數轉換程式套用到應用程式中的所有屬性路由。This convention applies a specified parameter transformer to all attribute routes in the app. 參數轉換程式會在被取代時轉換屬性路由語彙基元。The parameter transformer transforms attribute route tokens as they are replaced. 如需詳細資訊,請參閱使用參數轉換程式自訂語彙基元取代For more information, see Use a parameter transformer to customize token replacement.
  • Razor頁面具有 Microsoft.AspNetCore.Mvc.ApplicationModels.PageRouteTransformerConvention API 慣例。 Pages has the Microsoft.AspNetCore.Mvc.ApplicationModels.PageRouteTransformerConvention API convention. 此慣例會將指定的參數轉換器套用至所有自動探索的 Razor 頁面。This convention applies a specified parameter transformer to all automatically discovered Razor Pages. 參數轉換器會轉換頁面路由的資料夾和檔案名區段 Razor 。The parameter transformer transforms the folder and file name segments of Razor Pages routes. 如需詳細資訊,請參閱使用參數轉換程式自訂頁面路由For more information, see Use a parameter transformer to customize page routes.

URL 產生參考URL generation reference

下列範例示範如何在指定路由值字典和 RouteCollection 的情況下產生路由的連結。The following example shows how to generate a link to a route given a dictionary of route values and a RouteCollection.

app.Run(async (context) =>
{
    var dictionary = new RouteValueDictionary
    {
        { "operation", "create" },
        { "id", 123}
    };

    var vpc = new VirtualPathContext(context, null, dictionary, 
        "Track Package Route");
    var path = routes.GetVirtualPath(vpc).VirtualPath;

    context.Response.ContentType = "text/html";
    await context.Response.WriteAsync("Menu<hr/>");
    await context.Response.WriteAsync(
        $"<a href='{path}'>Create Package 123</a><br/>");
});

在上述範例的結尾產生的 VirtualPath/package/create/123The VirtualPath generated at the end of the preceding sample is /package/create/123. 字典提供「追蹤套件路由」範本 package/{operation}/{id}operationid 路由值。The dictionary supplies the operation and id route values of the "Track Package Route" template, package/{operation}/{id}. 如需詳細資訊,請參閱使用路由中介軟體一節或範例應用程式中的範例程式碼。For details, see the sample code in the Use Routing Middleware section or the sample app.

VirtualPathContext 建構函式的第二個參數是「環境值」** 的集合。The second parameter to the VirtualPathContext constructor is a collection of ambient values. 環境值便於使用,因為它們會限制開發人員必須在要求內容中指定的值數目。Ambient values are convenient to use because they limit the number of values a developer must specify within a request context. 目前要求的目前路由值被視為用於連結產生的環境值。The current route values of the current request are considered ambient values for link generation. 在 ASP.NET Core MVC 應用程式 HomeControllerAbout 動作中,您不需要指定控制器路由值以連結到 Index 動作—會使用 Home 的環境值。In an ASP.NET Core MVC app's About action of the HomeController, you don't need to specify the controller route value to link to the Index action—the ambient value of Home is used.

不符合參數的環境值會予以忽略。Ambient values that don't match a parameter are ignored. 當明確提供的值覆寫環境值時,也會忽略環境值。Ambient values are also ignored when an explicitly provided value overrides the ambient value. URL 中的比對是從左到右。Matching occurs from left to right in the URL.

明確提供但不符合路由區段的值會新增至查詢字串。Values explicitly provided but that don't match a segment of the route are added to the query string. 下表顯示使用路由範本 {controller}/{action}/{id?} 時的結果。The following table shows the result when using the route template {controller}/{action}/{id?}.

環境值Ambient Values 明確值Explicit Values 結果Result
controller = "Home"controller = "Home" action = "About"action = "About" /Home/About
controller = "Home"controller = "Home" controller = "Order", action = "About"controller = "Order", action = "About" /Order/About
controller = "Home", color = "Red"controller = "Home", color = "Red" action = "About"action = "About" /Home/About
controller = "Home"controller = "Home" action = "About", color = "Red"action = "About", color = "Red" /Home/About?color=Red

如果路由具有未對應至參數的預設值,且該值會明確提供,它必須符合預設值:If a route has a default value that doesn't correspond to a parameter and that value is explicitly provided, it must match the default value:

routes.MapRoute("blog_route", "blog/{*slug}",
    defaults: new { controller = "Blog", action = "ReadPost" });

連結產生只有在提供了 controlleraction 的相符值時,才會產生此路由的連結。Link generation only generates a link for this route when the matching values for controller and action are provided.

複雜區段Complex segments

複雜區段 (例如,[Route("/x{token}y")]) 會透過以非窮盡的方式,由右至左比對常值來處理。Complex segments (for example [Route("/x{token}y")]) are processed by matching up literals from right to left in a non-greedy way. 請參閱此程式碼以了解如何比對複雜區段的詳細解釋。See this code for a detailed explanation of how complex segments are matched. 程式法範例不是由 ASP.NET Core 使用,但它提供一個好的複雜區段解釋。The code sample is not used by ASP.NET Core, but it provides a good explanation of complex segments.

路由功能負責將要求 URI 對應至路由處理常式,並分派傳入要求。Routing is responsible for mapping request URIs to route handlers and dispatching an incoming requests. 路由定義於應用程式,並在該應用程式啟動時進行設定。Routes are defined in the app and configured when the app starts. 路由可以選擇性地從要求中所包含的 URL 擷取值,然後這些值就可用於處理要求。A route can optionally extract values from the URL contained in the request, and these values can then be used for request processing. 使用應用程式中已設定的路由,路由功能將能夠產生對應至路由處理常式的 URL。Using configured routes from the app, routing is able to generate URLs that map to route handlers.

若要使用 ASP.NET Core 2.1 中的最新路由情節,請將相容性版本指定為 Startup.ConfigureServices 中的 MVC 服務註冊:To use the latest routing scenarios in ASP.NET Core 2.1, specify the compatibility version to the MVC services registration in Startup.ConfigureServices:

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

重要

本文件涵蓋低階的 ASP.NET Core 路由。This document covers low-level ASP.NET Core routing. 如需 ASP.NET Core MVC 路由的資訊,請參閱 ASP.NET Core 中的路由至控制器動作For information on ASP.NET Core MVC routing, see ASP.NET Core 中的路由至控制器動作. 如需頁面中路由慣例的詳細資訊 Razor ,請參閱 RazorASP.NET Core 中的頁面路由和應用程式慣例For information on routing conventions in Razor Pages, see RazorASP.NET Core 中的頁面路由和應用程式慣例.

查看或下載範例程式碼 (如何下載) View or download sample code (how to download)

路由的基本概念Routing basics

大部分應用程式都應該選擇基本的描述性路由傳送配置,讓 URL 可讀且有意義。Most apps should choose a basic and descriptive routing scheme so that URLs are readable and meaningful. 預設慣例路由 {controller=Home}/{action=Index}/{id?}The default conventional route {controller=Home}/{action=Index}/{id?}:

  • 支援基本的描述性路由配置。Supports a basic and descriptive routing scheme.
  • 適合作為 UI 型應用程式的起點。Is a useful starting point for UI-based apps.

在特殊情況下,開發人員通常會使用屬性路由或專屬的慣例路由,新增額外的簡潔路由到應用程式的高流量區域 (例如,部落格和電子商務端點)。Developers commonly add additional terse routes to high-traffic areas of an app in specialized situations (for example, blog and ecommerce endpoints) using attribute routing or dedicated conventional routes.

Web API 應該使用屬性路由傳送來將應用程式功能模型建構為作業由 HTTP 指令動詞代表的資源集合。Web APIs should use attribute routing to model the app's functionality as a set of resources where operations are represented by HTTP verbs. 這表示相同邏輯資源上的許多作業 (例如,GET、POST) 都會使用相同的 URL。This means that many operations (for example, GET, POST) on the same logical resource will use the same URL. 屬性路由提供仔細設計 API 公用端點配置所需的控制層級。Attribute routing provides a level of control that's needed to carefully design an API's public endpoint layout.

Razor頁面應用程式會使用預設的傳統路由,在應用程式的Pages資料夾中提供已命名的資源。 Pages apps use default conventional routing to serve named resources in the Pages folder of an app. 還有其他慣例可讓您自訂 Razor 頁面路由行為。Additional conventions are available that allow you to customize Razor Pages routing behavior. 如需詳細資訊,請參閱 RazorASP.NET Core 中的頁面簡介RazorASP.NET Core 中的頁面路由和應用程式慣例For more information, see RazorASP.NET Core 中的頁面簡介 and RazorASP.NET Core 中的頁面路由和應用程式慣例.

URL 產生支援允許在不需要硬式編碼的 URL 來連結應用程式的情況下開發應用程式。URL generation support allows the app to be developed without hard-coding URLs to link the app together. 這項支援可讓您從基本路由設定開始,並在決定應用程式資源配置之後修改路由。This support allows for starting with a basic routing configuration and modifying the routes after the app's resource layout is determined.

路由會使用的路由 IRouter 執行來:Routing uses routes implementations of IRouter to:

  • 將傳入要求對應至「路由處理常式」**。Map incoming requests to route handlers.
  • 產生用於回應的 URL。Generate the URLs used in responses.

根據預設,應用程式有一個路由集合。By default, an app has a single collection of routes. 當要求抵達時,集合中的路由會依其存在於集合的順序進行處理。When a request arrives, the routes in the collection are processed in the order that they exist in the collection. 此架構會嘗試對集合中的每個路由呼叫 RouteAsync 方法,藉以比對傳入要求 URL 與集合中的路由。The framework attempts to match an incoming request URL to a route in the collection by calling the RouteAsync method on each route in the collection. 回應可以根據路由資訊使用路由來產生 URL (例如,針對重新導向或連結),因此避免硬式編碼的 URL,這有助於可維護性。A response can use routing to generate URLs (for example, for redirection or links) based on route information and thus avoid hard-coded URLs, which helps maintainability.

路由系統具有下列特性:The routing system has the following characteristics:

  • 使用路由範本語法以 Token 化路由參數來定義路由。Route template syntax is used to define routes with tokenized route parameters.
  • 允許傳統式和屬性式端點組態。Conventional-style and attribute-style endpoint configuration is permitted.
  • IRouteConstraint 可用來判斷 URL 參數是否包含對指定端點條件約束有效的值。IRouteConstraint is used to determine whether a URL parameter contains a valid value for a given endpoint constraint.
  • 應用程式模型(例如 MVC/ Razor Pages)會註冊其所有的路由,其具有可預測的路由案例執行。App models, such as MVC/Razor Pages, register all of their routes, which have a predictable implementation of routing scenarios.
  • 回應可以根據路由資訊使用路由來產生 URL (例如,針對重新導向或連結),因此避免硬式編碼的 URL,這有助於可維護性。A response can use routing to generate URLs (for example, for redirection or links) based on route information and thus avoid hard-coded URLs, which helps maintainability.
  • URL 是根據支援任意擴充性的路由所產生。URL generation is based on routes, which support arbitrary extensibility. IUrlHelper 提供方法來建立 URL。IUrlHelper offers methods to build URLs.

路由會透過 RouterMiddleware 類別連線到中介軟體管線。Routing is connected to the middleware pipeline by the RouterMiddleware class. ASP.NET CORE mvc會將路由新增至中介軟體管線,作為其設定的一部分,並處理 MVC 和 Razor 頁面應用程式中的路由。ASP.NET Core MVC adds routing to the middleware pipeline as part of its configuration and handles routing in MVC and Razor Pages apps. 若要了解如何使用路由作為獨立元件,請參閱使用路由中介軟體一節。To learn how to use routing as a standalone component, see the Use Routing Middleware section.

URL 比對URL matching

URL 比對是路由用來將傳入要求分派給「處理常式」** 的處理序。URL matching is the process by which routing dispatches an incoming request to a handler. 這個處理序是基於 URL 路徑中的資料,但是可以擴展為考慮要求中的任何資料。This process is based on data in the URL path but can be extended to consider any data in the request. 分派要求給不同處理常式的能力,是調整應用程式大小和複雜度的關鍵。The ability to dispatch requests to separate handlers is key to scaling the size and complexity of an app.

傳入要求將進入 RouterMiddleware,而後者會依序在每個路由上呼叫 RouteAsync 方法。Incoming requests enter the RouterMiddleware, which calls the RouteAsync method on each route in sequence. IRouter 執行個體可將 RouteContext.Handler 設定為非 Null 的 RequestDelegate,來選擇是否要「處理」** 要求。The IRouter instance chooses whether to handle the request by setting the RouteContext.Handler to a non-null RequestDelegate. 如果路由為要求設定了處理常式,則路由處理會停止,且會叫用該處理常式來處理要求。If a route sets a handler for the request, route processing stops, and the handler is invoked to process the request. 如果找不到處理要求的路由處理常式,中介軟體會將要求傳遞給要求管線中的下一個中介軟體。If no route handler is found to process the request, the middleware hands the request off to the next middleware in the request pipeline.

RouteAsync 的主要輸入是與目前要求建立關聯的 RouteContext.HttpContextThe primary input to RouteAsync is the RouteContext.HttpContext associated with the current request. RouteContext.HandlerRouteContext.RouteData 是在比對路由之後設定的輸出。The RouteContext.Handler and RouteContext.RouteData are outputs set after a route is matched.

呼叫 RouteAsync 的比對也會根據到目前為止所執行的要求處理,將 RouteContext.RouteData 的屬性設定為適當的值。A match that calls RouteAsync also sets the properties of the RouteContext.RouteData to appropriate values based on the request processing performed thus far.

RouteData.Values 是「路由值」** 的字典,而路由值產生自路由。RouteData.Values is a dictionary of route values produced from the route. 這些值通常是透過將 URL 語彙基元化來決定,可以用來接受使用者輸入,或在應用程式內做出進一步的分派決策。These values are usually determined by tokenizing the URL and can be used to accept user input or to make further dispatching decisions inside the app.

RouteData.DataTokens 是其他資料的屬性包,而這些資料與相符路由相關。RouteData.DataTokens is a property bag of additional data related to the matched route. 提供了 DataTokens 來支援與每個路由建立關聯的狀態資料,因此應用程式可以依據符合哪一個路由來制定決策。DataTokens are provided to support associating state data with each route so that the app can make decisions based on which route matched. 這些是開發人員定義的值,不會以任何方式影響路由的行為。These values are developer-defined and do not affect the behavior of routing in any way. 此外,儲藏在 RouteData.DataTokens 中的值可以是任何類型,對比之下,RouteData.Values 則必須可轉換成字串或可從字串轉換。Additionally, values stashed in RouteData.DataTokens can be of any type, in contrast to RouteData.Values, which must be convertible to and from strings.

RouteData.Routers 是成功符合要求的參與路由清單。RouteData.Routers is a list of the routes that took part in successfully matching the request. 路由可以用巢狀方式置於彼此內部。Routes can be nested inside of one another. Routers 屬性會透過導致產生相符項目的路由邏輯樹狀結構反映路徑。The Routers property reflects the path through the logical tree of routes that resulted in a match. 一般而言,Routers 中的第一個項目是路由集合,應該用於產生 URL。Generally, the first item in Routers is the route collection and should be used for URL generation. Routers 中的最後一個項目是相符的路由處理常式。The last item in Routers is the route handler that matched.

URL 產生URL generation

URL 產生是路由可用來依據一組路由值建立 URL 路徑的處理序。URL generation is the process by which routing can create a URL path based on a set of route values. 這可讓您在路由處理常式和存取它們的 URL 之間建立邏輯分隔。This allows for a logical separation between route handlers and the URLs that access them.

URL 產生遵循類似的反覆執行處理序,但開頭是呼叫路由集合 GetVirtualPath 方法的使用者或架構程式碼。URL generation follows a similar iterative process, but it starts with user or framework code calling into the GetVirtualPath method of the route collection. 每個「路由」** 會依序呼叫其 GetVirtualPath 方法,直到傳回非 Null 的 VirtualPathData 為止。Each route has its GetVirtualPath method called in sequence until a non-null VirtualPathData is returned.

GetVirtualPath 的主要輸入是:The primary inputs to GetVirtualPath are:

路由主要使用 ValuesAmbientValues 所提供的路由值,以決定是否可能產生 URL,以及要包含哪些值。Routes primarily use the route values provided by Values and AmbientValues to decide whether it's possible to generate a URL and what values to include. AmbientValues 是比對目前要求所產生的路由值集合。The AmbientValues are the set of route values that were produced from matching the current request. 相反地,Values 是指定如何產生目前作業所需之 URL 的路由值。In contrast, Values are the route values that specify how to generate the desired URL for the current operation. 提供了 HttpContext,以防路由應該取得服務或與目前內容建立關聯的其他資料。The HttpContext is provided in case a route should obtain services or additional data associated with the current context.

提示

VirtualPathContext.Values 視為 VirtualPathContext.AmbientValues 的覆寫項目集合。Think of VirtualPathContext.Values as a set of overrides for the VirtualPathContext.AmbientValues. URL 產生會嘗試重複使用來自目前要求的路由值,讓您使用相同路由或路由值產生連結的 URL。URL generation attempts to reuse route values from the current request to generate URLs for links using the same route or route values.

GetVirtualPath 的輸出是 VirtualPathDataThe output of GetVirtualPath is a VirtualPathData. VirtualPathDataRouteData 的平行處理。VirtualPathData is a parallel of RouteData. VirtualPathData 包含用於輸出 URL 的 VirtualPath,以及一些路由應該設定的其他屬性。VirtualPathData contains the VirtualPath for the output URL and some additional properties that should be set by the route.

VirtualPathData.VirtualPath 屬性包含路由所產生的「虛擬路徑」**。The VirtualPathData.VirtualPath property contains the virtual path produced by the route. 視您需求的不同,可能需要進一步處理路徑。Depending on your needs, you may need to process the path further. 如果您想要以 HTML 呈現產生的 URL,請在前面加上應用程式的基底路徑。If you want to render the generated URL in HTML, prepend the base path of the app.

VirtualPathData.Router 是成功產生 URL 的路由參考。The VirtualPathData.Router is a reference to the route that successfully generated the URL.

VirtualPathData.DataTokens 屬性是其他資料的字典,而這些資料與產生 URL 的路由相關。The VirtualPathData.DataTokens properties is a dictionary of additional data related to the route that generated the URL. 這是 RouteData.DataTokens 的平行處理。This is the parallel of RouteData.DataTokens.

建立路由Create routes

路由提供 Route 類別作為 IRouter 的標準實作。Routing provides the Route class as the standard implementation of IRouter. 在呼叫 RouteAsync 時,Route 會使用「路由範本」** 語法來定義將比對 URL 路徑的模式。Route uses the route template syntax to define patterns to match against the URL path when RouteAsync is called. 在呼叫 GetVirtualPath 時,Route 會使用相同的路由範本來產生 URL。Route uses the same route template to generate a URL when GetVirtualPath is called.

大部分的應用程式會藉由呼叫 MapRoute 或其中一個 IRouteBuilder 上定義的類似擴充方法來定建立路由。Most apps create routes by calling MapRoute or one of the similar extension methods defined on IRouteBuilder. 任何 IRouteBuilder 擴充方法都會建立 Route 的執行個體,並將它新增至路由集合。Any of the IRouteBuilder extension methods create an instance of Route and add it to the route collection.

MapRoute 不接受路由處理常式參數。MapRoute doesn't accept a route handler parameter. MapRoute 只會新增 DefaultHandler 所處理的路由。MapRoute only adds routes that are handled by the DefaultHandler. 預設處理常式為 IRouter,該處理常式可能無法處理要求。The default handler is an IRouter, and the handler might not handle the request. 例如,ASP.NET Core MVC 通常會設定為預設處理常式,只處理符合可用控制器和動作的要求。For example, ASP.NET Core MVC is typically configured as a default handler that only handles requests that match an available controller and action. 若要深入了解 MVC 中的路由功能,請參閱 ASP.NET Core 中的路由至控制器動作To learn more about routing in MVC, see ASP.NET Core 中的路由至控制器動作.

下列程式碼範例是典型 ASP.NET Core MVC 路由定義所使用的 MapRoute 呼叫範例:The following code example is an example of a MapRoute call used by a typical ASP.NET Core MVC route definition:

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

此範本會比對 URL 路徑,並擷取路由值。This template matches a URL path and extracts the route values. 例如,路徑 /Products/Details/17 會產生下列路由值:{ controller = Products, action = Details, id = 17 }For example, the path /Products/Details/17 generates the following route values: { controller = Products, action = Details, id = 17 }.

路由值是透過將 URL 路徑分割成區段,並比對每個區段與路由範本中的「路由參數」** 名稱來判定。Route values are determined by splitting the URL path into segments and matching each segment with the route parameter name in the route template. 路由參數為具名。Route parameters are named. 參數是透過以括弧 { ... } 括住參數名稱來定義。The parameters defined by enclosing the parameter name in braces { ... }.

上述範本也可以比對 URL 路徑 / 並產生值 { controller = Home, action = Index }The preceding template could also match the URL path / and produce the values { controller = Home, action = Index }. 發生這種情況是因為 {controller}{action} 路由參數有預設值,而 id 路由參數為選擇性參數。This occurs because the {controller} and {action} route parameters have default values and the id route parameter is optional. 路由參數名稱之後緊接著值的等號 (=) 會定義參數預設值。An equals sign (=) followed by a value after the route parameter name defines a default value for the parameter. 路由參數名稱之後的問號 (?) 會定義選擇性參數。A question mark (?) after the route parameter name defines an optional parameter.

在路由相符時,具有預設值的路由參數一定** 會產生路由值。Route parameters with a default value always produce a route value when the route matches. 如果沒有對應的 URL 路徑區段,選擇性參數不會產生路由值。Optional parameters don't produce a route value if there is no corresponding URL path segment. 如需路由範本情節和語法的詳細描述,請參閱路由範本參考一節。See the Route template reference section for a thorough description of route template scenarios and syntax.

在下列範例中,路由參數定義 {id:int} 會定義 id 路由參數的路由條件約束In the following example, the route parameter definition {id:int} defines a route constraint for the id route parameter:

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

此範本會符合 /Products/Details/17 等 URL 路徑,但不符合 /Products/Details/ApplesThis template matches a URL path like /Products/Details/17 but not /Products/Details/Apples. 路由條件約束會實作 IRouteConstraint,並檢查路由值以進行驗證。Route constraints implement IRouteConstraint and inspect route values to verify them. 在此範例中,路由值 id 必須可以轉換為整數。In this example, the route value id must be convertible to an integer. 如需架構所提供之路由條件約束的說明,請參閱路由條件約束參考See route-constraint-reference for an explanation of route constraints provided by the framework.

MapRoute 的其他多載接受 constraintsdataTokensdefaults 的值。Additional overloads of MapRoute accept values for constraints, dataTokens, and defaults. 這些參數通常是用來傳遞匿名類型的物件,其中匿名類型的屬性名稱符合路由參數名稱。The typical usage of these parameters is to pass an anonymously typed object, where the property names of the anonymous type match route parameter names.

下列 MapRoute 範例會建立對等的路由:The following MapRoute examples create equivalent routes:

routes.MapRoute(
    name: "default_route",
    template: "{controller}/{action}/{id?}",
    defaults: new { controller = "Home", action = "Index" });

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

提示

對於簡單的路由而言,定義條件約束和預設的內嵌語法可能很方便。The inline syntax for defining constraints and defaults can be convenient for simple routes. 不過,內嵌語法不支援某些情節 (例如資料語彙基元)。However, there are scenarios, such as data tokens, that aren't supported by inline syntax.

下列範例將示範一些其他情節:The following example demonstrates a few additional scenarios:

routes.MapRoute(
    name: "blog",
    template: "Blog/{*article}",
    defaults: new { controller = "Blog", action = "ReadArticle" });

上述範本會比對 /Blog/All-About-Routing/Introduction 等 URL 路徑,並擷取值 { controller = Blog, action = ReadArticle, article = All-About-Routing/Introduction }The preceding template matches a URL path like /Blog/All-About-Routing/Introduction and extracts the values { controller = Blog, action = ReadArticle, article = All-About-Routing/Introduction }. 即使範本中沒有任何對應的路由參數,路由也會產生 controlleraction 的預設路由值。The default route values for controller and action are produced by the route even though there are no corresponding route parameters in the template. 預設值可以在路由範本中指定。Default values can be specified in the route template. article 路由參數透過在路由參數名稱之前加上一個星號 (*) 來定義為 catch-allThe article route parameter is defined as a catch-all by the appearance of an asterisk (*) before the route parameter name. 全部擷取路由參數會擷取 URL 路徑的其餘部分,而且也可以符合空字串。Catch-all route parameters capture the remainder of the URL path and can also match the empty string.

下列範例會新增路由條件約束和資料語彙基元:The following example adds route constraints and data tokens:

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" });

上述範本會比對 /en-US/Products/5 等 URL 路徑,並擷取值 { controller = Products, action = Details, id = 5 } 和資料語彙基元 { locale = en-US }The preceding template matches a URL path like /en-US/Products/5 and extracts the values { controller = Products, action = Details, id = 5 } and the data tokens { locale = en-US }.

[區域變數] 視窗語彙基元

路由類別 URL 產生Route class URL generation

Route 類別也可以結合一組路由值與其路由範本來產生 URL。The Route class can also perform URL generation by combining a set of route values with its route template. 這在邏輯上是比對 URL 路徑的反向處理序。This is logically the reverse process of matching the URL path.

提示

若要進一步了解 URL 產生,請假設您想要產生的 URL,並考慮路由範本將會如何比對該 URL。To better understand URL generation, imagine what URL you want to generate and then think about how a route template would match that URL. 產生的值為何?What values would be produced? 這與 URL 產生在 Route 類別中的運作方式大致相同。This is the rough equivalent of how URL generation works in the Route class.

下列範例使用一般 ASP.NET Core MVC 預設路由:The following example uses a general ASP.NET Core MVC default route:

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

路由值為 { controller = Products, action = List } 時,會產生 URL /Products/ListWith the route values { controller = Products, action = List }, the URL /Products/List is generated. 路由值會取代對應的路由參數,以形成 URL 路徑。The route values are substituted for the corresponding route parameters to form the URL path. 由於 id 是選擇性路由參數,因此沒有 id 值也可以成功產生 URL。Since id is an optional route parameter, the URL is successfully generated without a value for id.

路由值為 { controller = Home, action = Index } 時,會產生 URL /With the route values { controller = Home, action = Index }, the URL / is generated. 所提供的路由值符合預設值,因此可以放心地省略這些預設值對應的區段。The provided route values match the default values, and the segments corresponding to the default values are safely omitted.

這兩個產生的 URL 會使用下列路由定義 (/Home/Index/) 反覆存取,並產生用來產生 URL 的相同路由值。Both URLs generated round-trip with the following route definition (/Home/Index and /) produce the same route values that were used to generate the URL.

注意

使用 ASP.NET Core MVC 的應用程式應該使用 UrlHelper 來產生 URL,而不是直接呼叫路由。An app using ASP.NET Core MVC should use UrlHelper to generate URLs instead of calling into routing directly.

如需 URL 產生的詳細資訊,請參閱 URI 產生參考一節。For more information on URL generation, see the Url generation reference section.

使用路由中介軟體Use routing middleware

參考應用程式專案檔中的 Microsoft.AspNetCore.App 中繼套件Reference the Microsoft.AspNetCore.App metapackage in the app's project file.

Startup.ConfigureServices 中,將路由新增至服務容器:Add routing to the service container in Startup.ConfigureServices:

public void ConfigureServices(IServiceCollection services)
{
    services.AddRouting();
}

路由必須設定在 Startup.Configure 方法中。Routes must be configured in the Startup.Configure method. 範例應用程式使用下列 API:The sample app uses the following APIs:

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);

下表顯示使用指定 URL 的回應。The following table shows the responses with the given URIs.

URIURI 回應Response
/package/create/3 Hello!Hello! Route values: [operation, create], [id, 3]Route values: [operation, create], [id, 3]
/package/track/-3 Hello!Hello! Route values: [operation, track], [id, -3]Route values: [operation, track], [id, -3]
/package/track/-3/ Hello!Hello! Route values: [operation, track], [id, -3]Route values: [operation, track], [id, -3]
/package/track/ 要求失敗,沒有相符項目。The request falls through, no match.
GET /hello/Joe Hi, Joe!Hi, Joe!
POST /hello/Joe 要求失敗,僅符合 HTTP GET。The request falls through, matches HTTP GET only.
GET /hello/Joe/Smith 要求失敗,沒有相符項目。The request falls through, no match.

如果您要設定單一路由,請呼叫傳入 IRouter 執行個體的 UseRouterIf you're configuring a single route, call UseRouter passing in an IRouter instance. 您不需要使用 RouteBuilderYou won't need to use RouteBuilder.

架構會提供一組擴充方法來建立路由 (RequestDelegateRouteBuilderExtensions):The framework provides a set of extension methods for creating routes (RequestDelegateRouteBuilderExtensions):

其中一些列出的方法 (例如 MapGet) 需要 RequestDelegateSome of listed methods, such as MapGet, require a RequestDelegate. 路由相符時,RequestDelegate 會作為「路由處理常式」** 使用。The RequestDelegate is used as the route handler when the route matches. 此系列中的其他方法允許設定中介軟體管線,以作為路由處理常式使用。Other methods in this family allow configuring a middleware pipeline for use as the route handler. 如果 Map* 方法不接受處理常式 (例如 MapRoute),則會使用 DefaultHandlerIf the Map* method doesn't accept a handler, such as MapRoute, it uses the DefaultHandler.

Map[Verb] 方法會使用條件約束,將路由限制為方法名稱中的 HTTP 指令動詞。The Map[Verb] methods use constraints to limit the route to the HTTP Verb in the method name. 如需範例,請參閱 MapGetMapVerbFor example, see MapGet and MapVerb.

路由範本參考Route template reference

大括弧 ({ ... }) 內的語彙基元定義路由相符時會繫結的「路由參數」**。Tokens within curly braces ({ ... }) define route parameters that are bound if the route is matched. 您可以在路由區段中定義多個路由參數,但其必須以常值分隔。You can define more than one route parameter in a route segment, but they must be separated by a literal value. 例如,{controller=Home}{action=Index} 不是有效的路由,因為 {controller}{action} 之間沒有任何常值。For example, {controller=Home}{action=Index} isn't a valid route, since there's no literal value between {controller} and {action}. 這些路由參數必須有一個名稱,並且可以指定其他屬性。These route parameters must have a name and may have additional attributes specified.

路由參數之外的常值文字 (例如,{id}) 和路徑分隔符號 / 必須符合 URL 中的文字。Literal text other than route parameters (for example, {id}) and the path separator / must match the text in the URL. 文字比對會區分大小寫,並以 URL 路徑的已解碼表示法為基礎。Text matching is case-insensitive and based on the decoded representation of the URLs path. 若要比對常值路由參數分隔符號 ({}),請重複字元 ({{}}) 來將分隔符號逸出。To match a literal route parameter delimiter ({ or }), escape the delimiter by repeating the character ({{ or }}).

URL 模式嘗試擷取具有選擇性副檔名的檔案名稱時,具有其他考量。URL patterns that attempt to capture a file name with an optional file extension have additional considerations. 以範本 files/{filename}.{ext?} 為例。For example, consider the template files/{filename}.{ext?}. filenameext 都存在值時,就會填入這兩個值。When values for both filename and ext exist, both values are populated. 如果 URL 中只有 filename 存在值,由於結尾的句點 (.) 是選擇性項目,因此路由相符。If only a value for filename exists in the URL, the route matches because the trailing period (.) is optional. 下列 URL 符合此路由:The following URLs match this route:

  • /files/myFile.txt
  • /files/myFile

您可以使用星號 (*) 作為路由參數的前置詞,以繫結至 URI 的其餘部分。You can use the asterisk (*) as a prefix to a route parameter to bind to the rest of the URI. 這稱為「全部擷取」** 參數。This is called a catch-all parameter. 例如,blog/{*slug} 符合以 /blog 開頭且其後有任何值 (這會指派給 slug 路由值) 的所有 URI。For example, blog/{*slug} matches any URI that starts with /blog and has any value following it, which is assigned to the slug route value. 全部擷取參數也可以符合空字串。Catch-all parameters can also match the empty string.

當使用路由產生 URL (包括路徑分隔符號 (/) 字元) 時,catch-all 參數會逸出適當的字元。The catch-all parameter escapes the appropriate characters when the route is used to generate a URL, including path separator (/) characters. 例如,路由值為 { path = "my/path" } 的路由 foo/{*path} 會產生 foo/my%2FpathFor example, the route foo/{*path} with route values { path = "my/path" } generates foo/my%2Fpath. 請注意逸出的斜線。Note the escaped forward slash.

路由參數可能有「預設值」**,指定方法是在參數名稱之後指定預設值,並以等號 (=) 分隔。Route parameters may have default values designated by specifying the default value after the parameter name separated by an equals sign (=). 例如,{controller=Home} 定義 Home 作為 controller 的預設值。For example, {controller=Home} defines Home as the default value for controller. 如果 URL 中沒有用於參數的任何值,則會使用預設值。The default value is used if no value is present in the URL for the parameter. 路由參數也可以設為選擇性,方法是在參數名稱結尾附加問號 (?),如 id? 中所示。Route parameters are made optional by appending a question mark (?) to the end of the parameter name, as in id?. 選擇性值與預設路由參數之間的差異在於,具有預設值的路由參數一定會產生值—選擇性參數只有在要求 URL 提供值時才會有值。The difference between optional values and default route parameters is that a route parameter with a default value always produces a value—an optional parameter has a value only when a value is provided by the request URL.

路由參數可能具有條件約束,這些條件約束必須符合與 URL 繫結的路由值。Route parameters may have constraints that must match the route value bound from the URL. 在路由參數名稱之後新增分號 (:) 和條件約束名稱,即可指定路由參數的「內嵌條件約束」**。Adding a colon (:) and constraint name after the route parameter name specifies an inline constraint on a route parameter. 如果條件約束需要引數,這些引數會在條件約束名稱後面以括弧 ((...)) 括住。If the constraint requires arguments, they're enclosed in parentheses ((...)) after the constraint name. 指定多個內嵌條件約束的方法是附加另一個冒號 (:) 和條件約束名稱。Multiple inline constraints can be specified by appending another colon (:) and constraint name.

條件約束名稱和引述會傳遞至 IInlineConstraintResolver 服務來建立 IRouteConstraint 的執行個體,以用於 URL 處理。The constraint name and arguments are passed to the IInlineConstraintResolver service to create an instance of IRouteConstraint to use in URL processing. 例如,路由範本 blog/{article:minlength(10)} 指定具有引數 10minlength 條件約束。For example, the route template blog/{article:minlength(10)} specifies a minlength constraint with the argument 10. 如需路由條件約束詳細資訊和架構所提供的條件約束清單,請參閱路由條件約束參考一節。For more information on route constraints and a list of the constraints provided by the framework, see the Route constraint reference section.

下表示範範例路由範本及其行為。The following table demonstrates example route templates and their behavior.

路由範本Route Template 範例比對 URIExample Matching URI 要求 URI…The request URI…
hello /hello 只比對單一路徑 /helloOnly matches the single path /hello.
{Page=Home} / 比對並將 Page 設定為 HomeMatches and sets Page to Home.
{Page=Home} /Contact 比對並將 Page 設定為 ContactMatches and sets Page to Contact.
{controller}/{action}/{id?} /Products/List 對應至 Products 控制器和 List 動作。Maps to the Products controller and List action.
{controller}/{action}/{id?} /Products/Details/123 對應至 Products 控制器和 Details 動作 (id 設定為 123)。Maps to the Products controller and Details action (id set to 123).
{controller=Home}/{action=Index}/{id?} / 對應至 Home 控制器和 Index 方法 (會忽略 id)。Maps to the Home controller and Index method (id is ignored).

使用範本通常是最簡單的路由方式。Using a template is generally the simplest approach to routing. 條件約束和預設值也可以在路由範本外部指定。Constraints and defaults can also be specified outside the route template.

提示

啟用記錄以查看內建路由實作 (例如 Route) 如何符合要求。Enable Logging to see how the built-in routing implementations, such as Route, match requests.

路由條件約束參考Route constraint reference

路由條件約束執行時機是出現符合傳入 URL 的項目,並將 URL 路徑語彙基元化成路由值時。Route constraints execute when a match has occurred to the incoming URL and the URL path is tokenized into route values. 路由條件約束通常會透過路由範本檢查相關聯的路由值,並對是否可接受值做出是/否決策。Route constraints generally inspect the route value associated via the route template and make a yes/no decision about whether or not the value is acceptable. 某些路由條件約束會使用路由值以外的資料,以考慮是否可以路由要求。Some route constraints use data outside the route value to consider whether the request can be routed. 例如,HttpMethodRouteConstraint 可以依據其 HTTP 指令動詞接受或拒絕要求。For example, the HttpMethodRouteConstraint can accept or reject a request based on its HTTP verb. 條件約束可用於路由要求和連結產生。Constraints are used in routing requests and link generation.

警告

請勿針對輸入驗證使用條件約束。Don't use constraints for input validation. 如果針對輸入驗證使用條件約束,則無效的輸入會導致產生「404 - 找不到」** 回應,而不是「400 - 錯誤要求」** 與適當的錯誤訊息。If constraints are used for input validation, invalid input results in a 404 - Not Found response instead of a 400 - Bad Request with an appropriate error message. 路由條件約束會用來釐清類似的路由,而不是用來驗證特定路由的輸入。Route constraints are used to disambiguate similar routes, not to validate the inputs for a particular route.

下表示範範例路由條件約束及其預期行為。The following table demonstrates example route constraints and their expected behavior.

constraint (條件約束)constraint 範例Example 範例相符項目Example Matches 附註Notes
int {id:int} 123456789, -123456789123456789, -123456789 符合任何整數Matches any integer
bool {active:bool} true, FALSEtrue, FALSE 符合 truefalse (不區分大小寫)Matches true or false (case-insensitive)
datetime {dob:datetime} 2016-12-31, 2016-12-31 7:32pm2016-12-31, 2016-12-31 7:32pm 符合不因文化特性而異的有效 DateTime 值。Matches a valid DateTime value in the invariant culture. 請參閱先前的警告。See preceding warning.
decimal {price:decimal} 49.99, -1,000.0149.99, -1,000.01 符合不因文化特性而異的有效 decimal 值。Matches a valid decimal value in the invariant culture. 請參閱先前的警告。See preceding warning.
double {weight:double} 1.234, -1,001.01e81.234, -1,001.01e8 符合不因文化特性而異的有效 double 值。Matches a valid double value in the invariant culture. 請參閱先前的警告。See preceding warning.
float {weight:float} 1.234, -1,001.01e81.234, -1,001.01e8 符合不因文化特性而異的有效 float 值。Matches a valid float value in the invariant culture. 請參閱先前的警告。See preceding warning.
guid {id:guid} CD2C1638-1638-72D5-1638-DEADBEEF1638, {CD2C1638-1638-72D5-1638-DEADBEEF1638}CD2C1638-1638-72D5-1638-DEADBEEF1638, {CD2C1638-1638-72D5-1638-DEADBEEF1638} 符合有效的 GuidMatches a valid Guid value
long {ticks:long} 123456789, -123456789123456789, -123456789 符合有效的 longMatches a valid long value
minlength(value) {username:minlength(4)} Rick 字串必須至少有 4 個字元String must be at least 4 characters
maxlength(value) {filename:maxlength(8)} Richard 字串不能超過 8 個字元String must be no more than 8 characters
length(length) {filename:length(12)} somefile.txt 字串長度必須剛好是 12 個字元String must be exactly 12 characters long
length(min,max) {filename:length(8,16)} somefile.txt 字串長度必須至少有 8 個字元,但不能超過 16 個字元String must be at least 8 and no more than 16 characters long
min(value) {age:min(18)} 19 整數值必須至少為 18Integer value must be at least 18
max(value) {age:max(120)} 91 整數值不能超過 120Integer value must be no more than 120
range(min,max) {age:range(18,120)} 91 整數值必須至少為 18,但不能超過 120Integer value must be at least 18 but no more than 120
alpha {name:alpha} Rick 字串必須包含一或多個字母字元 (a-z,不區分大小寫)String must consist of one or more alphabetical characters (a-z, case-insensitive)
regex(expression) {ssn:regex(^\\d{{3}}-\\d{{2}}-\\d{{4}}$)} 123-45-6789 字串必須符合規則運算式 (請參閱有關定義規則運算式的提示)String must match the regular expression (see tips about defining a regular expression)
required {name:required} Rick 用來強制執行在 URL 產生期間呈現非參數值Used to enforce that a non-parameter value is present during URL generation

以冒號分隔的多個條件約束,可以套用至單一參數。Multiple, colon-delimited constraints can be applied to a single parameter. 例如,下列條件約束會將參數限制在 1 或更大的整數值:For example, the following constraint restricts a parameter to an integer value of 1 or greater:

[Route("users/{id:int:min(1)}")]
public User GetUserById(int id) { }

警告

確認 URL 可以轉換成 CLR 類型的路由條件約束 (例如 intDateTime) 一律使用不因國別而異的文化特性。Route constraints that verify the URL and are converted to a CLR type (such as int or DateTime) always use the invariant culture. 這些條件約束假設 URL 不可當地語系化。These constraints assume that the URL is non-localizable. 架構提供的路由條件約束不會修改路由值中儲存的值。The framework-provided route constraints don't modify the values stored in route values. 所有從 URL 剖析而來的路由值會儲存為字串。All route values parsed from the URL are stored as strings. 例如,float 條件約束會嘗試將路由值轉換成浮點數,但轉換的值只能用來確認它可以轉換成浮點數。For example, the float constraint attempts to convert the route value to a float, but the converted value is used only to verify it can be converted to a float.

規則運算式Regular expressions

ASP.NET Core 架構將 RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvariant 新增至規則運算式建構函式。The ASP.NET Core framework adds RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvariant to the regular expression constructor. 如需這些成員的說明,請參閱 RegexOptionsSee RegexOptions for a description of these members.

規則運算式使用的分隔符號和語彙基元,類似於路由和 C# 語言所使用的分隔符號和語彙基元。Regular expressions use delimiters and tokens similar to those used by Routing and the C# language. 規則運算式的語彙基元必須逸出。Regular expression tokens must be escaped. 若要在路由中使用規則運算式 ^\d{3}-\d{2}-\d{4}$,運算式必須以字串中所提供的 \ (單一反斜線) 字元作為 C# 原始程式檔中的 \\ (雙反斜線) 字元,才能逸出 \ 字串逸出字元 (除非使用逐字字串常值)。To use the regular expression ^\d{3}-\d{2}-\d{4}$ in routing, the expression must have the \ (single backslash) characters provided in the string as \\ (double backslash) characters in the C# source file in order to escape the \ string escape character (unless using verbatim string literals). 若要逸出路由參數分隔符號字元 ({}[]),請在運算式中使用雙字元 ({{}[[]]).To escape routing parameter delimiter characters ({, }, [, ]), double the characters in the expression ({{, }, [[, ]]). 下表顯示規則運算式和逸出的版本。The following table shows a regular expression and the escaped version.

規則運算式Regular Expression 逸出的規則運算式Escaped Regular Expression
^\d{3}-\d{2}-\d{4}$ ^\\d{{3}}-\\d{{2}}-\\d{{4}}$
^[a-z]{2}$ ^[[a-z]]{{2}}$

路由中所使用的規則運算式通常以插入號 (^) 字元開頭,並符合字串的開始位置。Regular expressions used in routing often start with the caret (^) character and match starting position of the string. 運算式通常以貨幣符號 ($) 字元結尾,並符合字串的結尾。The expressions often end with the dollar sign ($) character and match end of the string. ^$ 字元可確保規則運算式符合整個路由參數值。The ^ and $ characters ensure that the regular expression match the entire route parameter value. 若不使用 ^$ 字元,規則運算式會比對字串內的所有部分字串,這通常不是您想要的結果。Without the ^ and $ characters, the regular expression match any substring within the string, which is often undesirable. 下表提供範例,並說明它們符合或無法符合的原因。The following table provides examples and explains why they match or fail to match.

運算式Expression StringString 比對Match 註解Comment
[a-z]{2} hellohello Yes 子字串相符項目Substring matches
[a-z]{2} 123abc456123abc456 Yes 子字串相符項目Substring matches
[a-z]{2} mzmz Yes 符合運算式Matches expression
[a-z]{2} MZMZ Yes 不區分大小寫Not case sensitive
^[a-z]{2}$ hellohello No 請參閱上述的 ^$See ^ and $ above
^[a-z]{2}$ 123abc456123abc456 No 請參閱上述的 ^$See ^ and $ above

如需規則運算式語法的詳細資訊,請參閱 .NET Framework 規則運算式For more information on regular expression syntax, see .NET Framework Regular Expressions.

若要將參數限制為一組已知的可能值,請使用規則運算式。To constrain a parameter to a known set of possible values, use a regular expression. 例如,{action:regex(^(list|get|create)$)} 只會將 action 路由值與 listgetcreate 相符。For example, {action:regex(^(list|get|create)$)} only matches the action route value to list, get, or create. 如果已傳入條件約束字典,字串 ^(list|get|create)$ 則是對等項目。If passed into the constraints dictionary, the string ^(list|get|create)$ is equivalent. 已傳入條件約束字典 (未內嵌在範本內) 的條件約束,即使不符合其中一個已知的條件約束,也會被視為規則運算式。Constraints that are passed in the constraints dictionary (not inline within a template) that don't match one of the known constraints are also treated as regular expressions.

自訂路由限制式Custom Route Constraints

除了內建的路由限制式之外,自訂路由限制式也可以透過實作 IRouteConstraint 介面來建立。In addition to the built-in route constraints, custom route constraints can be created by implementing the IRouteConstraint interface. IRouteConstraint 介面包含單一方法 Match,此方法會在滿足限制式時傳回 true,否則會傳回 falseThe IRouteConstraint interface contains a single method, Match, which returns true if the constraint is satisfied and false otherwise.

若要使用自訂 IRouteConstraint,路由限制式型別必須必須向應用程式的 ConstraintMap (在應用程式的服務容器中) 註冊。To use a custom IRouteConstraint, the route constraint type must be registered with the app's ConstraintMap in the app's service container. ConstraintMap 是一個目錄,它將路由限制式機碼對應到可驗證那些限制式的 IRouteConstraint 實作。A ConstraintMap is a dictionary that maps route constraint keys to IRouteConstraint implementations that validate those constraints. 更新應用程式的 ConstraintMap 時,可在 Startup.ConfigureServices 中於進行 services.AddRouting 呼叫時更新,或透過使用 services.Configure<RouteOptions> 直接設定 RouteOptions 來更新。An app's ConstraintMap can be updated in Startup.ConfigureServices either as part of a services.AddRouting call or by configuring RouteOptions directly with services.Configure<RouteOptions>. 例如:For example:

services.AddRouting(options =>
{
    options.ConstraintMap.Add("customName", typeof(MyCustomConstraint));
});

限制式接著能以一般方式套用到路由 (使用註冊限制式型別時使用名稱)。The constraint can then be applied to routes in the usual manner, using the name specified when registering the constraint type. 例如:For example:

[HttpGet("{id:customName}")]
public ActionResult<string> Get(string id)

URL 產生參考URL generation reference

下列範例示範如何在指定路由值字典和 RouteCollection 的情況下產生路由的連結。The following example shows how to generate a link to a route given a dictionary of route values and a RouteCollection.

app.Run(async (context) =>
{
    var dictionary = new RouteValueDictionary
    {
        { "operation", "create" },
        { "id", 123}
    };

    var vpc = new VirtualPathContext(context, null, dictionary, 
        "Track Package Route");
    var path = routes.GetVirtualPath(vpc).VirtualPath;

    context.Response.ContentType = "text/html";
    await context.Response.WriteAsync("Menu<hr/>");
    await context.Response.WriteAsync(
        $"<a href='{path}'>Create Package 123</a><br/>");
});

在上述範例的結尾產生的 VirtualPath/package/create/123The VirtualPath generated at the end of the preceding sample is /package/create/123. 字典提供「追蹤套件路由」範本 package/{operation}/{id}operationid 路由值。The dictionary supplies the operation and id route values of the "Track Package Route" template, package/{operation}/{id}. 如需詳細資訊,請參閱使用路由中介軟體一節或範例應用程式中的範例程式碼。For details, see the sample code in the Use Routing Middleware section or the sample app.

VirtualPathContext 建構函式的第二個參數是「環境值」** 的集合。The second parameter to the VirtualPathContext constructor is a collection of ambient values. 環境值便於使用,因為它們會限制開發人員必須在要求內容中指定的值數目。Ambient values are convenient to use because they limit the number of values a developer must specify within a request context. 目前要求的目前路由值被視為用於連結產生的環境值。The current route values of the current request are considered ambient values for link generation. 在 ASP.NET Core MVC 應用程式 HomeControllerAbout 動作中,您不需要指定控制器路由值以連結到 Index 動作—會使用 Home 的環境值。In an ASP.NET Core MVC app's About action of the HomeController, you don't need to specify the controller route value to link to the Index action—the ambient value of Home is used.

不符合參數的環境值會予以忽略。Ambient values that don't match a parameter are ignored. 當明確提供的值覆寫環境值時,也會忽略環境值。Ambient values are also ignored when an explicitly provided value overrides the ambient value. URL 中的比對是從左到右。Matching occurs from left to right in the URL.

明確提供但不符合路由區段的值會新增至查詢字串。Values explicitly provided but that don't match a segment of the route are added to the query string. 下表顯示使用路由範本 {controller}/{action}/{id?} 時的結果。The following table shows the result when using the route template {controller}/{action}/{id?}.

環境值Ambient Values 明確值Explicit Values 結果Result
controller = "Home"controller = "Home" action = "About"action = "About" /Home/About
controller = "Home"controller = "Home" controller = "Order", action = "About"controller = "Order", action = "About" /Order/About
controller = "Home", color = "Red"controller = "Home", color = "Red" action = "About"action = "About" /Home/About
controller = "Home"controller = "Home" action = "About", color = "Red"action = "About", color = "Red" /Home/About?color=Red

如果路由具有未對應至參數的預設值,且該值會明確提供,它必須符合預設值:If a route has a default value that doesn't correspond to a parameter and that value is explicitly provided, it must match the default value:

routes.MapRoute("blog_route", "blog/{*slug}",
    defaults: new { controller = "Blog", action = "ReadPost" });

連結產生只有在提供了 controlleraction 的相符值時,才會產生此路由的連結。Link generation only generates a link for this route when the matching values for controller and action are provided.

複雜區段Complex segments

複雜區段 (例如,[Route("/x{token}y")]) 會透過以非窮盡的方式,由右至左比對常值來處理。Complex segments (for example [Route("/x{token}y")]) are processed by matching up literals from right to left in a non-greedy way. 請參閱此程式碼以了解如何比對複雜區段的詳細解釋。See this code for a detailed explanation of how complex segments are matched. 程式法範例不是由 ASP.NET Core 使用,但它提供一個好的複雜區段解釋。The code sample is not used by ASP.NET Core, but it provides a good explanation of complex segments.