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

撰写者:Ryan NowakSteve SmithRick AndersonBy Ryan Nowak, Steve Smith, and Rick Anderson

路由负责将请求 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. 许多应用不需要添加模板所提供内容之外的路由。Many apps don't need to add routes beyond what the templates provide. 控制器和 Razor 页面的 ASP.NET Core 模板配置路由终结点。The ASP.NET Core templates for controllers and Razor pages configure route endpoints. 如果需要添加自定义路由终结点,则可以将自定义终结点与模板生成的路由终结点一起配置。If you need to add custom route endpoints, the custom endpoints can be configured alongside template generated route endpoints.

重要

本文档介绍较低级别的 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 Pages 中路由约定的信息,请参阅 ASP.NET Core 中 Razor 页面的路由和应用约定For information on routing conventions in Razor Pages, see ASP.NET Core 中 Razor 页面的路由和应用约定.

查看或下载示例代码如何下载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 应用使用默认的传统路由从应用的“页面”文件夹中提供命名资源 。Razor Pages apps use default conventional routing to serve named resources in the Pages folder of an app. 还可以使用其他约定来自定义 Razor Pages 路由行为。Additional conventions are available that allow you to customize Razor Pages routing behavior. 有关详细信息,请参阅 ASP.NET Core 中的 Razor 页面介绍ASP.NET Core 中 Razor 页面的路由和应用约定For more information, see ASP.NET Core 中的 Razor 页面介绍 and ASP.NET Core 中 Razor 页面的路由和应用约定.

借助 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 to implement cross-cutting concerns based on policies and configuration attached to each endpoint.

路由系统具有以下特征:The routing system has the following characteristics:

  • 路由模板语法用于通过标记化路由参数来定义路由。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:

备注

终结点链接仅限于 MVC/Razor Pages 操作和页。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 Pages 应用中的路由。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.

当路由中间件执行时,它会设置终结点 (Endpoint) 并将值路由到 HttpContext 上的功能。When a Routing Middleware executes, it sets an endpoint (Endpoint) and route values to a feature on the HttpContext. 对于当前请求:For the current request:

  • 调用 HttpContext.GetEndpoint 将获取终结点。Calling HttpContext.GetEndpoint gets the endpoint.
  • HttpRequest.RouteValues 将获取路由值的集合。HttpRequest.RouteValues gets the collection of route values.

在路由中间件之后运行的中间件可以看到终结点并采取措施。Middleware running after the Routing Middleware can see 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. 由于中间件是基于所选终结点来应用策略,因此任何可能影响调度或安全策略应用的决策都应在路由系统内部制定,这一点很重要。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 的 URL 生成URL 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 的方案(如 Tag Helpers、HTML Helpers 和 Action Results)使用链接生成器提供链接生成功能。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. 例如,许多用户熟悉的来自 MVC/Razor Pages 的路由名称和路由值方案都是作为地址方案实现的。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.

使用地址调用 LinkGeneratorLinkGenerator 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:

  • 对于不验证传入请求的 Host 标头的应用配置,请谨慎使用 GetUri* 扩展方法。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.

  • 在中间件中将 LinkGeneratorMapMapWhen 结合使用时,请小心谨慎。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.

终结点路由Endpoint routing

  • 路由终结点具有模板、元数据以及为终结点响应提供服务的请求委托。A route endpoint has a template, metadata, and a request delegate that serves the endpoint's response. 元数据用于实现横切关注点,该实现基于附加到每个终结点的策略和配置。The metadata is used to implement cross-cutting concerns based on policies and configuration attached to each endpoint. 例如,授权中间件可以在终结点的元数据集合中询问授权策略For example, an authorization middleware can interrogate the endpoint's metadata collection for an authorization policy.
  • 终结点路由使用两个扩展方法与中间件集成:Endpoint routing integrates with middleware using two extension methods:
    • UseRouting 向中间件管道添加路由匹配。UseRouting adds route matching to the middleware pipeline. 它必须在任何路由感知中间件(如授权、终结点执行等)之前。It must come before any route-aware middleware such as authorization, endpoint execution, etc.
    • UseEndpoints 向中间件管道添加终结点执行。UseEndpoints adds endpoint execution to the middleware pipeline. 它运行为终结点响应提供服务的请求委托。It runs the request delegate that serves the endpoint's response. 此外,UseEndpoints 还是配置可由应用匹配和执行的路由终结点的位置。UseEndpoints is also where route endpoints are configured that can be matched and executed by the app. 例如:MapRazorPagesMapControllersMapGetMapPostFor example, MapRazorPages, MapControllers, MapGet, and MapPost.
  • 应用使用 ASP.NET Core 的 Helper 方法来配置其路由。Apps use ASP.NET Core's helper methods to configure their routes. ASP.NET Core 框架提供了 MapRazorPagesMapControllersMapHub<THub> 等 Helper 方法。ASP.NET Core frameworks provide helper methods like MapRazorPages,, MapControllers and MapHub<THub>. 还提供了用于配置自己的自定义路由终结点的 Helper 方法:MapGetMapPostMapVerbThere are also helper methods for configuring your own custom route endpoints: MapGet, MapPost, and MapVerb.
  • 终结点路由还支持在应用程序启动后更改终结点。Endpoint routing also supports endpoints changing after an application has started up. 若要在应用或 ASP.NET Core 框架中支持这一点,必须创建并注册自定义 EndpointDataSourceTo support this in your app or ASP.NET Core framework, a custom EndpointDataSource must be created and registered. 这是一项高级功能,通常不需要。This is an advanced feature, and usually not needed. 终结点通常在启动时配置,并且在应用的生存期内是静态的。Endpoints are typically configured at startup and are static for the lifetime of the app. 在启动时从文件或数据库加载路由配置不是动态的。Loading route configuration from a file or database at startup is not dynamic.

以下代码演示终结点路由的基本示例:The following code shows a basic example of endpoint routing:

public void Configure(IApplicationBuilder app)
{
    // Matches request to an endpoint.
    app.UseRouting();

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

    // Execute the matched endpoint.
    app.UseEndpoints(endpoints =>
    {
        // Configuration of app endpoints.
        endpoints.MapRazorPages();
        endpoints.MapGet("/", context => context.Response.WriteAsync("Hello world"));
        endpoints.MapHealthChecks("/healthz");
    });
}

有关终结点路由的详细信息,请参阅本文档中的 URL 匹配See URL matching in this document for more information on endpoint routing.

终结点路由与早期版本路由的差异Endpoint routing differences from earlier versions of routing

比 ASP.NET Core 2.2 更早的版本中的终结点路由与版本路由之间存在一些差异:A few differences exist between endpoint routing and versions of routing earlier than in ASP.NET Core 2.2:

  • 终结点路由系统不支持基于 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 的路由,此代码生成 URI /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.

  • 在试图链接到不存在的控制器/操作或页面时,MVC/Razor 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 的路由,即使 BlogController 不存在或没有 ReadPost 操作方法,结果也始终为 /Blog/ReadPost/17With 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 Core2.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?}"
    

    如果 ASP.NET Core 2.1 或更早版本中的 URI 为 /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 路由值可能是用户 ID 值,而非存储产品 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 ({*myparametername}) 早期版本中的单星号 catch-all 参数语法仍然受支持,并对正斜杠进行编码。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. 应用中的任何类都可通过将链接生成器注入类并调用 GenerateLink 来使用链接生成器。Using 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

大多数应用通过调用 MapRouteIRouteBuilder 上定义的一种类似的扩展方法来创建路由。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 was 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 而不是 /Products/Details/Apples 的 URL 路径相匹配。This 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-all 。The 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 }.

本地 Windows 令牌

路由类 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 是可选路由参数,因此成功生成的 URL 不具有 id 的值。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 生成的详细信息,请参阅 Url 生成参考部分。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);

下表显示了具有给定 URI 的响应。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)} 使用参数 10 指定 minlength 约束。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.

路由参数还可以具有参数转换器,用于在生成链接以及将操作和页面匹配到 URI 时转换参数的值。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} trueFALSEtrue, FALSE 匹配 truefalse(区分大小写)Matches true or false (case-insensitive)
datetime {dob:datetime} 2016-12-312016-12-31 7:32pm2016-12-31, 2016-12-31 7:32pm 匹配有效的 DateTime 值(位于固定区域性中 - 查看警告)Matches a valid DateTime value (in the invariant culture - see warning)
decimal {price:decimal} 49.99-1,000.0149.99, -1,000.01 匹配有效的 decimal 值(位于固定区域性中 - 查看警告)Matches a valid decimal value (in the invariant culture - see warning)
double {weight:double} 1.234-1,001.01e81.234, -1,001.01e8 匹配有效的 double 值(位于固定区域性中 - 查看警告)Matches a valid double value (in the invariant culture - see warning)
float {weight:float} 1.234-1,001.01e81.234, -1,001.01e8 匹配有效的 float 值(位于固定区域性中 - 查看警告)Matches a valid float value (in the invariant culture - see 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.CultureInvariantThe 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 路由值匹配到 listgetcreateFor 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 可作为 services.AddRouting 调用的一部分在 Startup.ConfigureServices 中进行更新,也可以通过使用 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.

例如,路由模式 blog\{article:slugify}(具有 Url.Action(new { article = "MyTestArticle" }))中的自定义 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 使用参数转换器来转换用于匹配 area``controller``actionpage 的路由值。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 Pages 具有 Microsoft.AspNetCore.Mvc.ApplicationModels.PageRouteTransformerConvention API 约定。Razor Pages has the Microsoft.AspNetCore.Mvc.ApplicationModels.PageRouteTransformerConvention API convention. 此约定将指定的参数转换器应用于所有自动发现的 Razor Pages。This convention applies a specified parameter transformer to all automatically discovered Razor Pages. 参数转换器转换 Razor Pages.路由的文件夹和文件名段。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 操作中,无需指定控制器路由值即可链接到使用 Home 环境值的 Index 操作—。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
控制器 =“Home”controller = "Home" 操作 =“About”action = "About" /Home/About
控制器 =“Home”controller = "Home" 控制器 =“Order”,操作 =“About”controller = "Order", action = "About" /Order/About
控制器 = “Home”,颜色 = “Red”controller = "Home", color = "Red" 操作 =“About”action = "About" /Home/About
控制器 =“Home”controller = "Home" 操作 =“About”,颜色 =“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.

配置终结点元数据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.comHost: www.domain.com (matches www.domain.com with any port)
  • 带有通配符的主机:*.domain.com(匹配任何端口上的 www.domain.comsubdomain.domain.comwww.subdomain.domain.comHost 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, *.domain.com:5000 (matches host and port)

可以使用 RequireHost[Host] 指定多个参数。Multiple parameters can be specified using RequireHost or [Host]. 约束将匹配对任何参数有效的主机。The constraint will match hosts valid for any of the parameters. 例如,[Host("domain.com", "*.domain.com")] 将匹配 domain.comwww.domain.comsubdomain.domain.comFor example, [Host("domain.com", "*.domain.com")] will match domain.com, www.domain.com, or 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("Hi AdventureWorks!"))
            .RequireHost("adventure-works.com");
        endpoints.MapHealthChecks("/healthz").RequireHost("*:8080");
    });
}

以下代码使用 [Host] 属性来要求控制器上的指定主机:The following code uses the [Host] attribute to require the specified host on the controller:

[Host("contoso.com", "adventure-works.com")]
public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;

    public HomeController(ILogger<HomeController> logger)
    {
        _logger = logger;
    }

    public IActionResult Index()
    {
        return View();
    }

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

}

[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.

路由负责将请求 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 选项确定路由是应在内部使用 ASP.NET Core 2.1 或更早版本的基于终结点的逻辑还是使用其基于 IRouter 的逻辑。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 Pages 中路由约定的信息,请参阅 ASP.NET Core 中 Razor 页面的路由和应用约定For information on routing conventions in Razor Pages, see ASP.NET Core 中 Razor 页面的路由和应用约定.

查看或下载示例代码如何下载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 应用使用默认的传统路由从应用的“页面”文件夹中提供命名资源 。Razor Pages apps use default conventional routing to serve named resources in the Pages folder of an app. 还可以使用其他约定来自定义 Razor Pages 路由行为。Additional conventions are available that allow you to customize Razor Pages routing behavior. 有关详细信息,请参阅 ASP.NET Core 中的 Razor 页面介绍ASP.NET Core 中 Razor 页面的路由和应用约定For more information, see ASP.NET Core 中的 Razor 页面介绍 and ASP.NET Core 中 Razor 页面的路由和应用约定.

借助 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:

  • 路由模板语法用于通过标记化路由参数来定义路由。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 Pages 应用中的路由。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 的 URL 生成URL 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 的方案(如 Tag Helpers、HTML Helpers 和 Action Results)使用链接生成器提供链接生成功能。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. 例如,许多用户熟悉的来自 MVC/Razor Pages 的路由名称和路由值方案都是作为地址方案实现的。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.

使用地址调用 LinkGeneratorLinkGenerator 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:

  • 对于不验证传入请求的 Host 标头的应用配置,请谨慎使用 GetUri* 扩展方法。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.

  • 在中间件中将 LinkGeneratorMapMapWhen 结合使用时,请小心谨慎。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 的路由,此代码生成 URI /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.

  • 在试图链接到不存在的控制器/操作或页面时,MVC/Razor 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 的路由,即使 BlogController 不存在或没有 ReadPost 操作方法,结果也始终为 /Blog/ReadPost/17With 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 Core2.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?}"
    

    如果 ASP.NET Core 2.1 或更早版本中的 URI 为 /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 路由值可能是用户 ID 值,而非存储产品 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 ({*myparametername}) 早期版本中的单星号 catch-all 参数语法仍然受支持,并对正斜杠进行编码。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. 应用中的任何类都可通过将链接生成器注入类并调用 GenerateLink 来使用链接生成器。Using 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

大多数应用通过调用 MapRouteIRouteBuilder 上定义的一种类似的扩展方法来创建路由。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 was 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 而不是 /Products/Details/Apples 的 URL 路径相匹配。This 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-all 。The 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 }.

本地 Windows 令牌

路由类 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 是可选路由参数,因此成功生成的 URL 不具有 id 的值。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 生成的详细信息,请参阅 Url 生成参考部分。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);

下表显示了具有给定 URI 的响应。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)} 使用参数 10 指定 minlength 约束。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.

路由参数还可以具有参数转换器,用于在生成链接以及将操作和页面匹配到 URI 时转换参数的值。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} trueFALSEtrue, FALSE 匹配 truefalse(区分大小写)Matches true or false (case-insensitive)
datetime {dob:datetime} 2016-12-312016-12-31 7:32pm2016-12-31, 2016-12-31 7:32pm 匹配有效的 DateTime 值(位于固定区域性中 - 查看警告)Matches a valid DateTime value (in the invariant culture - see warning)
decimal {price:decimal} 49.99-1,000.0149.99, -1,000.01 匹配有效的 decimal 值(位于固定区域性中 - 查看警告)Matches a valid decimal value (in the invariant culture - see warning)
double {weight:double} 1.234-1,001.01e81.234, -1,001.01e8 匹配有效的 double 值(位于固定区域性中 - 查看警告)Matches a valid double value (in the invariant culture - see warning)
float {weight:float} 1.234-1,001.01e81.234, -1,001.01e8 匹配有效的 float 值(位于固定区域性中 - 查看警告)Matches a valid float value (in the invariant culture - see 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.CultureInvariantThe 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 路由值匹配到 listgetcreateFor 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 可作为 services.AddRouting 调用的一部分在 Startup.ConfigureServices 中进行更新,也可以通过使用 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.

例如,路由模式 blog\{article:slugify}(具有 Url.Action(new { article = "MyTestArticle" }))中的自定义 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 使用参数转换器来转换用于匹配 area``controller``actionpage 的路由值。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 Pages 具有 Microsoft.AspNetCore.Mvc.ApplicationModels.PageRouteTransformerConvention API 约定。Razor Pages has the Microsoft.AspNetCore.Mvc.ApplicationModels.PageRouteTransformerConvention API convention. 此约定将指定的参数转换器应用于所有自动发现的 Razor Pages。This convention applies a specified parameter transformer to all automatically discovered Razor Pages. 参数转换器转换 Razor Pages.路由的文件夹和文件名段。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 操作中,无需指定控制器路由值即可链接到使用 Home 环境值的 Index 操作—。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
控制器 =“Home”controller = "Home" 操作 =“About”action = "About" /Home/About
控制器 =“Home”controller = "Home" 控制器 =“Order”,操作 =“About”controller = "Order", action = "About" /Order/About
控制器 = “Home”,颜色 = “Red”controller = "Home", color = "Red" 操作 =“About”action = "About" /Home/About
控制器 =“Home”controller = "Home" 操作 =“About”,颜色 =“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 Pages 中路由约定的信息,请参阅 ASP.NET Core 中 Razor 页面的路由和应用约定For information on routing conventions in Razor Pages, see ASP.NET Core 中 Razor 页面的路由和应用约定.

查看或下载示例代码如何下载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 应用使用默认的传统路由从应用的“页面”文件夹中提供命名资源 。Razor Pages apps use default conventional routing to serve named resources in the Pages folder of an app. 还可以使用其他约定来自定义 Razor Pages 路由行为。Additional conventions are available that allow you to customize Razor Pages routing behavior. 有关详细信息,请参阅 ASP.NET Core 中的 Razor 页面介绍ASP.NET Core 中 Razor 页面的路由和应用约定For more information, see ASP.NET Core 中的 Razor 页面介绍 and ASP.NET Core 中 Razor 页面的路由和应用约定.

借助 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:

  • 路由模板语法用于通过标记化路由参数来定义路由。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 Pages 应用中的路由。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 的 VirtualPathDataEach 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. 如果路由应获取与当前上下文关联的服务或其他数据时,则提供 HttpContextThe 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. Route 使用 route template 语法来定义模式,以便在调用 RouteAsync 时匹配 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.

大多数应用通过调用 MapRouteIRouteBuilder 上定义的一种类似的扩展方法来创建路由。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 was 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 而不是 /Products/Details/Apples 的 URL 路径相匹配。This 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-all 。The 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 }.

本地 Windows 令牌

路由类 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 是可选路由参数,因此成功生成的 URL 不具有 id 的值。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 生成的详细信息,请参阅 Url 生成参考部分。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);

下表显示了具有给定 URI 的响应。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 实例中调用 UseRouter 传入。If 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. 这称为 catch-all 参数 。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)} 使用参数 10 指定 minlength 约束。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.

保留的路由名称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} trueFALSEtrue, FALSE 匹配 truefalse(区分大小写)Matches true or false (case-insensitive)
datetime {dob:datetime} 2016-12-312016-12-31 7:32pm2016-12-31, 2016-12-31 7:32pm 匹配有效的 DateTime 值(位于固定区域性中 - 查看警告)Matches a valid DateTime value (in the invariant culture - see warning)
decimal {price:decimal} 49.99-1,000.0149.99, -1,000.01 匹配有效的 decimal 值(位于固定区域性中 - 查看警告)Matches a valid decimal value (in the invariant culture - see warning)
double {weight:double} 1.234-1,001.01e81.234, -1,001.01e8 匹配有效的 double 值(位于固定区域性中 - 查看警告)Matches a valid double value (in the invariant culture - see warning)
float {weight:float} 1.234-1,001.01e81.234, -1,001.01e8 匹配有效的 float 值(位于固定区域性中 - 查看警告)Matches a valid float value (in the invariant culture - see 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.CultureInvariantThe 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 路由值匹配到 listgetcreateFor 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 可作为 services.AddRouting 调用的一部分在 Startup.ConfigureServices 中进行更新,也可以通过使用 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 操作中,无需指定控制器路由值即可链接到使用 Home 环境值的 Index 操作—。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
控制器 =“Home”controller = "Home" 操作 =“About”action = "About" /Home/About
控制器 =“Home”controller = "Home" 控制器 =“Order”,操作 =“About”controller = "Order", action = "About" /Order/About
控制器 = “Home”,颜色 = “Red”controller = "Home", color = "Red" 操作 =“About”action = "About" /Home/About
控制器 =“Home”controller = "Home" 操作 =“About”,颜色 =“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.