ASP.NET Web API 2中的属性路由(Attribute Routing)

如何启用属性路由并描述属性路由的各种选项?

Why Attribute Routing?

Web API的第一个版本使用基于约定的路由。在这种类型的路由中,您可以定义一个或多个路由模板,这些模板基本上是参数化字符串。当框架收到请求时,它会将URI与路由模板进行匹配。

基于约定的路由的一个优点是模板在单个位置定义,并且路由规则在所有控制器上一致地应用。遗憾的是,基于约定的路由使得很难支持RESTful API中常见的某些URI模式。例如,资源通常包含子资源:客户有订单,电影有演员,书有作者,等等。创建反映这些关系的URI是很自然的:

/customers/1/orders

使用基于约定的路由很难创建这种类型的URI。尽管可以这样做,但如果您有许多控制器或资源类型,结果将无法很好地扩展。

使用属性路由,为此URI定义路由很简单。您只需向控制器操作添加一个属性:

[Route("customers/{customerId}/orders")]
public IEnumerable<Order> GetOrdersByCustomer(int customerId) { ... }

启用属性路由:Enabling Attribute Routing

要启用属性路由,请在WebApiConfig配置文件调用MapHttpAttributeRoutes。此扩展方法在System.Web.Http.HttpConfigurationExtensions类中定义。

using System.Web.Http;

namespace WebApplication
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API routes
            config.MapHttpAttributeRoutes();

            // Other Web API configuration not shown.
        }
    }
}

属性路由可以与基于约定的路由组合。要定义基于约定的路由,请调用MapHttpRoute方法:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Attribute routing.
        config.MapHttpAttributeRoutes();

        // Convention-based routing.
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }
}

注意:从Web API 1迁移

在Web API 2之前,Web API项目模板生成如下代码:

protected void Application_Start()
{
    // WARNING - Not compatible with attribute routing.
    WebApiConfig.Register(GlobalConfiguration.Configuration);
}

如果启用了属性路由,则此代码将引发异常。如果升级现有Web API项目以使用属性路由,请确保将此配置代码更新为以下内容:

protected void Application_Start()
{
    // Pass a delegate to the Configure method.
    GlobalConfiguration.Configure(WebApiConfig.Register);
}

添加路由属性:Adding Route Attributes

以下是使用属性定义的路径示例:

public class OrdersController : ApiController
{
    [Route("customers/{customerId}/orders")]
    [HttpGet]
    public IEnumerable<Order> FindOrdersByCustomer(int customerId) { ... }
}

字符串“customers / {customerId} / orders”是路径的URI模板。Web API尝试将请求URI与模板匹配。在此示例中,“customers”和“orders”是文字段,“{customerId}”是可变参数。以下URI将与此模板匹配:

  • http://localhost/customers/1/orders
  • http://localhost/customers/bob/orders
  • http://localhost/customers/1234-5678/orders

请注意,路由模板中的“{customerId}”参数与方法中customerId参数的名称相匹配。

当Web API调用控制器操作时,它会尝试绑定路由参数。例如,如果URI为http://example.com/customers/1/orders,则Web API会尝试将值“1”绑定到操作中的customerId参数。

任何没有路由属性的控制器方法都使用基于约定的路由。这样,您可以在同一个项目中组合两种类型的路由。

HTTP方法

Web API还根据请求的HTTP方法(GET,POST等)选择操作。默认情况下,Web API会查找与控制器方法名称的开头不区分大小写的匹配项。例如,控制器方法名:PutCustomers匹配 HTTP PUT请求。

您可以通过使用以下任何属性修饰方法来覆盖此约定:

  • [HttpDelete]
  • [HTTPGET]
  • [HttpHead]
  • [HttpOptions]
  • [HttpPatch]
  • [HttpPost]
  • [HttpPut]

以下示例将CreateBook方法映射到HTTP POST请求。

[Route("api/books")]
[HttpPost]
public HttpResponseMessage CreateBook(Book book) { ... }

对于所有其他HTTP方法(包括非标准方法),请使用AcceptVerbs属性,该属性采用HTTP方法列表

// WebDAV method
[Route("api/books")]
[AcceptVerbs("MKCOL")]
public void MakeCollection() { }

路由前缀:Route Prefixes

通常,控制器中的路由都以相同的前缀开头。例如:

public class BooksController : ApiController
{
    [Route("api/books")]
    public IEnumerable<Book> GetBooks() { ... }

    [Route("api/books/{id:int}")]
    public Book GetBook(int id) { ... }

    [Route("api/books")]
    [HttpPost]
    public HttpResponseMessage CreateBook(Book book) { ... }
}

您可以使用[RoutePrefix]属性为整个控制器设置公共前缀:

[RoutePrefix("api/books")]
public class BooksController : ApiController
{
    // GET api/books
    [Route("")]
    public IEnumerable<Book> Get() { ... }

    // GET api/books/5
    [Route("{id:int}")]
    public Book Get(int id) { ... }

    // POST api/books
    [Route("")]
    public HttpResponseMessage Post(Book book) { ... }
}

在method属性上使用波浪号(?)来覆盖路由前缀:

[RoutePrefix("api/books")]
public class BooksController : ApiController
{
    // GET /api/authors/1/books
    [Route("~/api/authors/{authorId:int}/books")]
    public IEnumerable<Book> GetByAuthor(int authorId) { ... }

    // ...
}

路由前缀可以包含参数:

[RoutePrefix("customers/{customerId}")]
public class OrdersController : ApiController
{
    // GET customers/1/orders
    [Route("orders")]
    public IEnumerable<Order> Get(int customerId) { ... }
}

路由约束:Route Constraints

路由约束允许您限制路径模板中的参数匹配方式。一般语法是“{parameter:constraint}”。例如:

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

[Route("users/{name}")]
public User GetUserByName(string name) { ... }

下表列出了支持的约束:

Constraint Description Example
alpha Matches uppercase or lowercase Latin alphabet characters (a-z, A-Z) {x:alpha}
bool Matches a Boolean value. {x:bool}
datetime Matches a DateTime value. {x:datetime}
decimal Matches a decimal value. {x:decimal}
double Matches a 64-bit floating-point value. {x:double}
float Matches a 32-bit floating-point value. {x:float}
guid Matches a GUID value. {x:guid}
int Matches a 32-bit integer value. {x:int}
length Matches a string with the specified length or within a specified range of lengths. {x:length(6)} {x:length(1,20)}
long Matches a 64-bit integer value. {x:long}
max Matches an integer with a maximum value. {x:max(10)}
maxlength Matches a string with a maximum length. {x:maxlength(10)}
min Matches an integer with a minimum value. {x:min(10)}
minlength Matches a string with a minimum length. {x:minlength(10)}
range Matches an integer within a range of values. {x:range(10,50)}
regex Matches a regular expression. {x:regex(^\d{3}-\d{3}-\d{4}$)}

请注意,某些约束(例如“min”)在括号中包含参数。您可以将多个约束应用于参数,以冒号分隔。

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

自定义路由约束:Custom Route Constraints

您可以通过实现IHttpRouteConstraint接口来创建自定义路由约束。例如,以下约束将参数限制为非零整数值。

public class NonZeroConstraint : IHttpRouteConstraint
{
    public bool Match(HttpRequestMessage request, IHttpRoute route, string parameterName,
        IDictionary<string, object> values, HttpRouteDirection routeDirection)
    {
        object value;
        if (values.TryGetValue(parameterName, out value) && value != null)
        {
            long longValue;
            if (value is long)
            {
                longValue = (long)value;
                return longValue != 0;
            }

            string valueString = Convert.ToString(value, CultureInfo.InvariantCulture);
            if (Int64.TryParse(valueString, NumberStyles.Integer,
                CultureInfo.InvariantCulture, out longValue))
            {
                return longValue != 0;
            }
        }
        return false;
    }
}

以下代码显示了如何注册约束:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        var constraintResolver = new DefaultInlineConstraintResolver();
        constraintResolver.ConstraintMap.Add("nonzero", typeof(NonZeroConstraint));

        config.MapHttpAttributeRoutes(constraintResolver);
    }
}

现在您可以在路由中应用约束:

[Route("{id:nonzero}")]
public HttpResponseMessage GetNonZero(int id) { ... }

您还可以通过实现IInlineConstraintResolver接口替换整个DefaultInlineConstraintResolver类。这样做将替换所有内置约束,除非您的IInlineConstraintResolver实现专门添加它们。

可选的URI参数和默认值

您可以通过向路由参数添加问号来使URI参数可选。如果route参数是可选的,则必须为method参数定义默认值。

public class BooksController : ApiController
{
    [Route("api/books/locale/{lcid:int?}")]
    public IEnumerable<Book> GetBooksByLocale(int lcid = 1033) { ... }
}

在这个例子中,/api/books/locale/1033/api/books/locale返回相同的资源。

或者,您可以在路径模板中指定默认值,如下所示:

public class BooksController : ApiController
{
    [Route("api/books/locale/{lcid:int=1033}")]
    public IEnumerable<Book> GetBooksByLocale(int lcid) { ... }
}

路由名称:Route Names

在Web API中,每个路由都有一个名称。路由名称对于生成链接非常有用,因此您可以在HTTP响应中包含链接。

要指定路由名称,请在属性上设置Name属性。以下示例显示如何设置路由名称,以及如何在生成链接时使用路由名称。

public class BooksController : ApiController
{
    [Route("api/books/{id}", Name="GetBookById")]
    public BookDto GetBook(int id)
    {
        // Implementation not shown...
    }

    [Route("api/books")]
    public HttpResponseMessage Post(Book book)
    {
        // Validate and add book to database (not shown)

        var response = Request.CreateResponse(HttpStatusCode.Created);

        // Generate a link to the new book and set the Location header in the response.
        string uri = Url.Link("GetBookById", new { id = book.BookId });
        response.Headers.Location = new Uri(uri);
        return response;
    }
}

路由顺序:Route Order

当框架尝试将URI与路由匹配时,它会按特定顺序评估路由。要指定顺序,请在route属性上设置RouteOrder属性。首先评估较低的值。默认排序值为零。

以下是确定总排序的方式:

  1. 比较route属性的RouteOrder属性。
  2. 查看路由模板中的每个URI段。对于每个细分,顺序如下:
    1. 文字片段。
    2. 使用约束路由参数。
    3. 路由参数没有约束。
    4. 具有约束的通配符参数段。
    5. 没有约束的通配符参数段。
  3. In the case of a tie,,路由按路由模板的不区分大小写的序列比较(OrdinalIgnoreCase排序
[RoutePrefix("orders")]
public class OrdersController : ApiController
{
    [Route("{id:int}")] // constrained parameter
    public HttpResponseMessage Get(int id) { ... }

    [Route("details")]  // literal
    public HttpResponseMessage GetDetails() { ... }

    [Route("pending", RouteOrder = 1)]
    public HttpResponseMessage GetPending() { ... }

    [Route("{customerName}")]  // unconstrained parameter
    public HttpResponseMessage GetByCustomer(string customerName) { ... }

    [Route("{*date:datetime}")]  // wildcard
    public HttpResponseMessage Get(DateTime date) { ... }
}

这些路由按如下顺序排列.

  1. orders/details
  2. orders/{id}
  3. orders/{customerName}
  4. orders/{*date}
  5. orders/pending

原文地址:https://www.cnblogs.com/AndyChen2015/p/9592015.html

时间: 2024-11-08 13:03:33

ASP.NET Web API 2中的属性路由(Attribute Routing)的相关文章

Asp.Net Web API 2第八课——Web API 2中的属性路由

参考页面: http://www.yuanjiaocheng.net/webapi/web-api-gaisu.html http://www.yuanjiaocheng.net/webapi/create-web-api-proj.html http://www.yuanjiaocheng.net/webapi/test-webapi.html http://www.yuanjiaocheng.net/webapi/web-api-controller.html http://www.yuan

在ASP.NET Web API项目中使用Hangfire实现后台任务处理

当前项目中有这样一个需求:由前端用户的一个操作,需要触发到不同设备的消息推送.由于推送这个具体功能,我们采用了第三方的服务.而这个服务调用有时候可能会有延时,为此,我们希望将消息推送与用户前端操作实现异步执行,就是希望在后台自动执行,不阻塞前端用户的操作,而且最好能实现失败重试等功能. 经过一些研究比较,我们发现使用Hangfire这个组件可以较好地实现这个需求.为了给大家做一个演示,我这里简化了代码,做一个范例程序. 我在这里不准备详细介绍Hangfire的基本用法,有兴趣的同学们可以参考官方

在ASP.NET Web API 2中使用Owin OAuth 刷新令牌

在上篇文章介绍了Web Api中使用令牌进行授权的后端实现方法,基于WebApi2和OWIN OAuth实现了获取access token,使用token访问需授权的资源信息.本文将介绍在Web Api中启用刷新令牌的后端实现. 本文要用到上篇文章所使用的代码,代码编写环境为VS 2017..Net Framework 4.7.2,数据库为MS SQL 2008 R2. OAuth 刷新令牌 上文已经搞了一套Token授权访问,这里有多出来一个刷新令牌(Refresh Token),平白添加程序

ASP.NET Web API路由系统:路由系统的几个核心类型

虽然ASP.NET Web API框架采用与ASP.NET MVC框架类似的管道式设计,但是ASP.NET Web API管道的核心部分(定义在程序集System.Web.Http.dll中)已经移除了对System.Web.dll程序集的依赖,实现在ASP.NET Web API框架中的URL路由系统亦是如此.也就是说,ASP.NET Web API核心框架的URL路由系统与ASP.NET本身的路由系统是相对独立的.但是当我们采用基于Web Host的方式(定义在程序集System.Web.H

IoC在ASP.NET Web API中的应用

参考页面: http://www.yuanjiaocheng.net/webapi/create-crud-api-1-get.html http://www.yuanjiaocheng.net/webapi/create-crud-api-1-post.html http://www.yuanjiaocheng.net/webapi/create-crud-api-1-put.html http://www.yuanjiaocheng.net/webapi/create-crud-api-1-

【Web API系列教程】2.2 — ASP.NET Web API中的路由和动作选择机制

这篇文章描述了ASP.NET Web API如何将HTTP请求路由到控制器上的特定动作. 备注:想要了解关于路由的高层次概述,请查看Routing in ASP.NET Web API. 这篇文章侧重于路由过程的细节.如果你创建了一个Web API项目并且发现一些请求并没有按你预期得到相应的路由,希望这篇文章有所帮助. 路由有以下三个主要阶段: 将URI匹配到路由模板 选择一个控制器 选择一个动作 你可以用自己的习惯行为来替换其中一些过程.在本文中,我会描述默认行为.在结尾,我会指出你可以自定义

ASP.NET Web API WebHost宿主环境中管道、路由

ASP.NET Web API WebHost宿主环境中管道.路由 前言 上篇中说到ASP.NET Web API框架在SelfHost环境中管道.路由的一个形态,本篇就来说明一下在WebHost环境中ASP.NET Web API框架中的管道.路由又是哪一种形态. ASP.NET Web API路由.管道 ASP.NET Web API 开篇介绍示例 ASP.NET Web API 路由对象介绍 ASP.NET Web API 管道模型 ASP.NET Web API selfhost宿主环境

ASP.NET Web API 过滤器创建、执行过程(一)

前言 在上一篇中我们讲到控制器的执行过程系列,这个系列要搁置一段时间了,因为在控制器执行的过程中包含的信息都是要单独的用一个系列来描述的,就如今天的这个篇幅就是在上面内容之后所看到的一个知识要点之一. ASP.NET Web API 过滤器创建.执行过程(一) 下面就来讲解一下在ASP.NET Web API框架中过滤器的创建.执行过程. 过滤器所在的位置 图1 图1所示的就是控制器执行过程很粗略的表示. 通过上一篇内容我们了解到控制器方法选择器最后返回的并不是控制器方法,而是对于控制器方法描述

ASP.NET Web API Model-ModelBinder

ASP.NET Web API Model-ModelBinder 前言 本篇中会为大家介绍在ASP.NET Web API中ModelBinder的绑定原理以及涉及到的一些对象模型,还有简单的Model绑定示例,在前面的篇幅中讲解了Model元数据.ValueProvider的模块,然后还有本篇的Model绑定的模块这些会结合到后面篇幅中的ParameterBinder模块中来使用,也就是说在ASP.NET Web API框架中绑定的方式有两种实现,都是通过ParameterBinder来对参