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/ordershttp://localhost/customers/bob/ordershttp://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 != ;
} string valueString = Convert.ToString(value, CultureInfo.InvariantCulture);
if (Int64.TryParse(valueString, NumberStyles.Integer,
CultureInfo.InvariantCulture, out longValue))
{
return longValue != ;
}
}
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 = ) { ... }
}
在这个例子中,/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属性。首先评估较低的值。默认排序值为零。
以下是确定总排序的方式:
比较route属性的RouteOrder属性。
查看路由模板中的每个URI段。对于每个细分,顺序如下:
- 文字片段。
- 使用约束路由参数。
- 路由参数没有约束。
- 具有约束的通配符参数段。
- 没有约束的通配符参数段。
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 = )]
public HttpResponseMessage GetPending() { ... }
[Route("{customerName}")] // unconstrained parameter
public HttpResponseMessage GetByCustomer(string customerName) { ... }
[Route("{*date:datetime}")] // wildcard
public HttpResponseMessage Get(DateTime date) { ... }
}
这些路由按如下顺序排列.
- orders/details
- orders/{id}
- orders/{customerName}
- orders/{*date}
- orders/pending
ASP.NET Web API 2中的属性路由(Attribute Routing)的更多相关文章
- ASP.NET Web API 2 中的属性路由使用(转载)
转载地址:ASP.NET Web API 2 中的属性路由使用
- Web API 2中的属性路由
Web API 2中的属性路由 前言 阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok/p/3446289.ht ...
- Asp.Net Web API 2第八课——Web API 2中的属性路由
前言 阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok/p/3446289.html 路由就是Web API如何 ...
- ASP.NET Web API 2 中的特性路由
ASP.NET MVC 5.1 开始已经支持基于特性的路由(http://attributerouting.net),ASP.NET WEB API 2 同时也支持了这一特性. 启用特性路 由只需要在 ...
- ASP.NET Web API 2.0新特性:Attribute Routing1
ASP.NET Web API 2.0新特性:Attribute Routing[上篇] 对于一个针对ASP.NET Web API的调用请求来说,请求的URL和对应的HTTP方法的组合最终决定了目标 ...
- 【ASP.NET Web API教程】4.2 路由与动作选择
原文:[ASP.NET Web API教程]4.2 路由与动作选择 注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本系列教程,请先看前面的内容. 4.2 Routing ...
- [翻译]ASP.NET Web API 2 中的全局错误处理
目录 已存在的选项 解决方案预览 设计原则 什么时候去用 方案详情 示例 附录: 基类详情 原文链接 Global Error Handling in ASP.NET Web API 2 由于翻译水平 ...
- 在ASP.NET Web API 2中使用Owin基于Token令牌的身份验证
基于令牌的身份验证 基于令牌的身份验证主要区别于以前常用的常用的基于cookie的身份验证,基于cookie的身份验证在B/S架构中使用比较多,但是在Web Api中因其特殊性,基于cookie的身份 ...
- 在ASP.NET Web API项目中使用Hangfire实现后台任务处理
当前项目中有这样一个需求:由前端用户的一个操作,需要触发到不同设备的消息推送.由于推送这个具体功能,我们采用了第三方的服务.而这个服务调用有时候可能会有延时,为此,我们希望将消息推送与用户前端操作实现 ...
随机推荐
- Excle中range的一些用法
以下是一些range的简单用法 Sub aa() '-=============================================== '给B列设置填充颜色为黄色 Range(" ...
- smartcar 系列机器人学习笔记1
总体框架: 1,感知一个相机,一个雷达,一个odom(非必须:一个imu)功能:车道线检测,红绿灯检测,障碍物检测 2,决策规划 功能:一次规划,(避障即:二次规划) 3,控制执行 功能:速度控制,角 ...
- 特殊文件权限(setuid、setgid 和 Sticky 位)
可执行文件和公共目录可以使用三种特殊类型的权限:setuid.setgid 和 sticky 位.设置这些权限之后,运行可执行文件的任何用户都应采用该可执行文件属主(或组)的 ID. setuid 权 ...
- Python 代码块左移或右移
(就 IDE 是 PyCharm 来说) 选中代码块: 1)右移:直接 Tab 2)左移:Shift + Tab Python 对代码对齐要求很严格的. Python的对齐方式很重要,对齐方式决定了 ...
- angular绑定数据 使用循环输出列表数据
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script sr ...
- python相关性分析与p值检验
## 最近两天的成果 ''' ########################################## # # # 不忘初心 砥砺前行. # # 418__yj # ########### ...
- HTTPSConnectionPool(host='xxxxx', port=443): Max retries exceeded with url:xxxxxxxx (Caused by NewConnectionError('<urllib3.connect,Max retries exceeded with ,(Caused by NewConnectionError
HTTPSConnectionPool(host='f6ws-sha8re-o88k.s3.ama66zaws.com', port=443): Max retries exceeded with u ...
- [css]后台管理系统布局
知识点: 绝对定位+overflowhidden 整体思路 三大块 pg-header---需要固定 (height:48px) pg-content menu 右侧菜单-需要固定(width:200 ...
- PHPCMS V9数据库表结构分析
PHPCMS V9可以轻松承载百万级的访问数据,最大的功臣就是PHPCMS良好的数据库结构,在数据库的设计方面,一定是下足了功夫. 一般网站的信息量离这个级别相差甚远,但是了解学习一下PHPCMS ...
- Installing OwnCloud 9 on Debian 8
原文:https://www.howtoforge.com/tutorial/owncloud_9-installation-on-debian_8/?utm_source=tuicool&u ...