ASP.NET Web API 中的属性路由
为什么要有属性路由
基于约定路由的一个优点是模板在单个位置中定义,并且路由规则在所有控制器上一致的应用。但是基于约定的路由很难支持RESTFUl 中常见的某些URI模式。例如,资源通常包含子资源,客户有订单,电影有演员,书有作者等等。创建反应这些URI是很自然的,如下图所示:
/customers/1/orders
使用属性路由,为此URI定义路由很简单,只需向控制器中添加一个属性,如下图所示:
[Route("customers/{customerId}/orders")]
public IEnumerable<Order> GetOrdersByCustomer(int customerId) { ... }
启用属性路由
要启用属性路由,要在配置期间调用MapHttpAttributeRoutes,此方法在System.Web.Http.HttpConfigurationExtensions类中定义。如下图所示:
using System.Web.Http;namespace WebApplication
{public static class WebApiConfig{public static void Register(HttpConfiguration config){// Web API routesconfig.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 });}
}
添加属性路由
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相匹配,当WebAPI调用控制器操作时,它会尝试绑定路由参数。例如 URI为 http://example.com/customers/1/orders ,则Web API会尝试将 值“1”绑定到操作的customerId参数中。
URI模板中可以有多个参数,如下图所示:
[Route("customers/{customerId}/orders/{orderId}")]
public Order GetOrderByCustomer(int customerId, int orderId) { ... }
Web API还根据请求的Http方法(Get,Post等)选择操作。默认情况下,Web API会查找与控制器方法名称的开头不区分大小写的匹配项。例如,控制器方法PutCustomer匹配HTTP PUT请求。
以下示例将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() { }
路由前缀
通常,控制器的中的路由都以相同的前缀开头,例如:
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) { ... }
}
路径约束允许限制路径模板中的参数匹配方式。一般语法是“{parameter:constraint}”。例如:
[Route("users/{id:int}")]
public User GetUserById(int id) { ... }[Route("users/{name}")]
public User GetUserByName(string name) { ... }
这时候,只有id是整数时,才匹配第一路径。否则,将选择第二路径。完整的约束列表如下图所示:
约束 | 描述 | 例子 |
alpha | 匹配大写或者小写拉丁字母:(a-z , A-Z) | {x:alpha} |
bool | 匹配布尔类型 | {x:bool} |
datetime | 匹配DataTime类型 | {x:datetime} |
decimal | 匹配小数值 | {x:decimal} |
double | 匹配64位浮点数 | {x:double} |
float | 匹配32位浮点数 | {x:float} |
guid | 匹配Guid值 | {x:guid} |
int | 匹配32位整型 | {x:int} |
length | 匹配具有指定长度或者具有指定长度范围的字符串 | {x:length(6)} {x:length(1,20)} |
long | 匹配64位整数值 | {x:long} |
max | 匹配具有最大值的整数 | {x:max(10)} |
maxlength | 匹配具有最大长度的字符串 | {x:maxlength(10)} |
min | 匹配具有最小值的整数 | {x:min(10)} |
minlength | 匹配具有最小长度的字符串 | {x:minlength(10)} |
range | 匹配值范围内的整数 | {x:range(10,50)} |
regex | 匹配正则表达式 | {x:regex(^\d{3}-\d{3}-\d{4}$)} |
可以将多个约束应用于参数,以冒号分隔
[Route("users/{id:int:min(1)}")]
public User GetUserById(int id) { ... }
可以通过实现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) { ... }
可选的URI参数和默认值
可以通过向路由参数添加问号来使URI参数可选。如果route参数是可选的,则必须为方法参数定义默认值
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) { ... }
}
路由名称
在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;}
}
路由顺序
当框架尝试将URI与路由匹配时,它会按特定的顺序评估路由,要指定顺序,需要在Route属性上设置Order属性,框架首先评估Order值较低的方法,默认Order值为零。
以下是确定总排序的方式:
1、比较Route属性的Order属性。
2、查看路由模板中的每个URI片段,对于细分,约定如下:
a、静态片段。
b、使用约束路由参数。
c、路由参数没有约束。
d、具有约束的通配符参数段
e、没有约束的通配符参数段
[RoutePrefix("orders")]
public class OrdersController : ApiController
{[Route("{id:int}")] // constrained parameterpublic HttpResponseMessage Get(int id) { ... }[Route("details")] // literalpublic HttpResponseMessage GetDetails() { ... }[Route("pending", RouteOrder = 1)]public HttpResponseMessage GetPending() { ... }[Route("{customerName}")] // unconstrained parameterpublic HttpResponseMessage GetByCustomer(string customerName) { ... }[Route("{*date:datetime}")] // wildcardpublic HttpResponseMessage Get(DateTime date) { ... }
}
以上路由将按以下顺序执行:
1、orders/details
2、orders/{id}
3、orders/{customerName}
4、orders/{*date}
5、orders/pending
ASP.NET Web API 中的属性路由相关推荐
- ASP.NET Web API中的Controller
虽然通过Visual Studio向导在ASP.NET Web API项目中创建的 Controller类型默认派生与抽象类型ApiController,但是ASP.NET Web API框架本身只要 ...
- ASP.NET Web API中实现版本
一般来说,api 接口是提供给其他系统或是其他公司使用,不能随意频繁的变更.然而,需求和业务不断变化,接口和参数也会发生相应的变化.如果直接对原来的接口进行修改,势必会影响线其他系统的正常运行.这就必 ...
- 监控系统简介(二):使用 App Metrics 在 ASP.NET Web API 中记录指标
回顾 在<监控系统简介:使用 Prometheus 与 Grafana>一文中,我们了解了什么是监控系统,Prometheus 这一监控工具及它提供的数据类型.PromQL 以及 Graf ...
- ASP.NET Web API中的参数绑定总结
ASP.NET Web API中的action参数类型可以分为简单类型和复杂类型. HttpResponseMessage Put(int id, Product item) id是int类型,是简单 ...
- 【ASP.NET Web API教程】5.5 ASP.NET Web API中的HTTP Cookie
5.5 HTTP Cookies in ASP.NET Web API 5.5 ASP.NET Web API中的HTTP Cookie 本文引自:http://www.asp.net/web-api ...
- ASP.NET Web API中实现版本的几种方式
在ASP.NET Web API中,当我们的API发生改变,就涉及到版本问题了.如何实现API的版本呢? 1.通过路由设置版本 最简单的一种方式是通过路由设置,不同的路由,不同的版本,不同的contr ...
- 利用查询条件对象,在Asp.net Web API中实现对业务数据的分页查询处理
在Asp.net Web API中,对业务数据的分页查询处理是一个非常常见的接口,我们需要在查询条件对象中,定义好相应业务的查询参数,排序信息,请求记录数和每页大小信息等内容,根据这些查询信息,我们在 ...
- (四)Asp.net web api中的坑-【api的返回值】
(四)Asp.net web api中的坑-[api的返回值] 原文:(四)Asp.net web api中的坑-[api的返回值] void无返回值 IHttpActionResult HttpRe ...
- 在ASP.NET Web API中使用OData的Action和Function
本篇体验OData的Action和Function功能.上下文信息参考"ASP.NET Web API基于OData的增删改查,以及处理实体间关系".在本文之前,我存在的疑惑包括: ...
最新文章
- 即将到来的金三银四,这10道springboot常见面试题你需要了解下
- ASP.NET 应用程序生命周期概述
- jQuery 常用的效果函数(一)
- 摇杆控制方向原理_医用无油空压机的送料作用及工作原理
- VSS SVN GIT SVN 加锁签出
- ASP语言基础之常量的定义方法
- switch安装linux教程,Freeswitch Linux安装教程 | 【韩涛博客】
- 加速包可能没用!12306屏蔽多个抢票软件
- Python——数据存储:JSON操作
- PREV-55 小计算器 (进制转换)
- C++ 类使用规范建议
- SQLyog下载地址—Mysql的可视化(建议收藏)
- javascript边角知识
- SoftCnKiller高速下载器捆绑软件杀手
- 软件推荐:论文翻译阅读 + 文献管理 + markdown笔记 + 多设备同步 + 一键导出bib参考文献
- vant组件做表格_有赞团队的vant ui组件库van-field使用
- 联想Lenovo手机平板安装谷歌服务框架Google, Play商店,安装套件GMS
- 用Excel绘制曲线图
- ThingWorx入门
- 线程池ExecutorService
热门文章
- python练习笔记——利用信号signal处理僵尸进程
- 右击菜单一键优化(增加新建office2003、新建reg和bat,删除新建公文包、新建wps、新建rar)...
- 创建laravel项目
- [nodejs] 利用openshift 撰寫應用喔
- zabbix邮件通知,短信通知配置详解
- 多年以后重发:多线程安全的变量模板
- asp.net 实现一级域名与二级域名共享COOKIE
- 关于C语言野指针的问题
- Spring AOP两种使用方式以及如何使用解析
- [转载] Java面试题大全(2020版)