Asp.Net Web API 2第六课——Web API路由和动作选择

简介: 原文:Asp.Net Web API 2第六课——Web API路由和动作选择Asp.Net Web API 导航       Asp.Net Web API第一课——入门http://www.cnblogs.
原文: Asp.Net Web API 2第六课——Web API路由和动作选择

Asp.Net Web API 导航

      Asp.Net Web API第一课——入门http://www.cnblogs.com/aehyok/p/3432158.html

      Asp.Net Web API第二课——CRUD操作http://www.cnblogs.com/aehyok/p/3434578.html

      Asp.Net Web API第三课——.NET客户端调用Web API http://www.cnblogs.com/aehyok/p/3439698.html

      Asp.Net Web API第四课——HttpClient消息处理器 http://www.cnblogs.com/aehyok/p/3442277.html

  Asp.Net Web API第五课——Web API路由 http://www.cnblogs.com/aehyok/p/3442051.html

前言

  本文描述ASP.NET Web API如何把一个HTTP请求路由到控制器的一个特定的Action上。关于路由的总体概述可以参见上一篇教程 http://www.cnblogs.com/aehyok/p/3442051.html。这篇文章主要来学习路由过程的细节。如果你创建了一个Web API项目,发现有一些请求没有按照你期望的方式被路由,希望这篇文章将对你有所帮助。

      本文主要分为三个阶段:

  1.匹配URI到一个Route Template。

  2.选择一个Controller。

  3.选择一个Action。

  你可以用自己的自定义行为来替换这一过程中的某些部分。在本文中,我将来描述默认的行为。在文章结尾,我会注明可以在什么地方自定义行为。

 

  

Route Templates

 路由模版看上去类似于一个URI路径,但它可以具有占位符,并用花括号来指示:

"api/{controller}/public/{category}/{id}"

当创建一个路由的时候,你可以为某些或所有占位符提供默认值:

defaults: new { category = "all" }

你也可以提供约束,它限制URI片段如何与占位符匹配:

constraints: new { id = @"\d+" }   // Only matches if "id" is one or more digits.

上面语句是通过正则表达式来限制片段的取值,上面的注释说明 id片段只匹配一个或多个数字,因此URI中的id片段必须是数字才能与这个路由进行匹配。

 

这个框架试图把URI路径中的片段与这个模板进行匹配。模板中的文字必须严格匹配。一个占位符可以匹配任何值,除非你指定了约束。这个框架不会匹配URI另外的部分,例如主机名或者一个查询字符串。这个框架会选择路由表中第一个匹配的路由。

这里有两个特殊的占位符:“{controller}”和“{action}”。

  • “{controller}”提供控制器名。
  • “{action}”提供动作名。在Web API中,通常的约定是忽略“{action}”的。

Defaults(默认值)

如果你提供默认值,那么这个路由将匹配缺少这些片段的URI。例如:

routes.MapHttpRoute(
    name: "DefaultApi", 
    routeTemplate: "api/{controller}/{category}", 
    defaults: new { category = "all" } 
);

这个URI“http://localhost/api/products”与这个路由是匹配的。“{category}”片段被赋成了默认值“all”。

Route Dictionary(路由字典)

  如果这个框架发现了一个匹配的URI,它会创建包含每个占位符值的一个字典。这个键值是不带花括号的的占位符名称。这个值取自于URI路径或者是默认值中的。这个字段被存在IHttpRouteData对象中。在匹配路由阶段,这个特殊的"{controller}" and "{action}"占位符的处理和其他占位符是一样的。它们用另外的值被简单的存储在字典中。

  在默认值中可以使用特殊的RouteParameter.Optional值。如果一个占位符被赋予了这个值,那么这个值将不会被添加到路由字典中,例如:

routes.MapHttpRoute( 
    name: "DefaultApi", 
    routeTemplate: "api/{controller}/{category}/{id}", 
    defaults: new { category = "all", id = RouteParameter.Optional } 
);

对于URI路径“api/products”,路由字典将含有:controller:"products"、category:"all"。

然而,对于“api/products/toys/123”,路由字典将含有:controller:"products"、category:"toys"、id:"123"。

 

这个默认值也可以包含未出现在路由模板中的值。若这条路由匹配,则该值会被存储在路由字典中。例如:

routes.MapHttpRoute( 
    name: "Root", 
    routeTemplate: "api/root/{id}", 
    defaults: new { controller = "customers", id = RouteParameter.Optional } 
);

如果URI路径是“api/root/8”,字典将含有两个值:controller:“customers”,id:"8"。

Selecting a Controller

控制器选择是由IHttpControllerSelector.SelectController方法来处理的。这个方法以HttpRequestMessage实例为参数,并返回HttpControllerDescriptor

其默认实现是由DefaultHttpControllerSelector类提供的。这个类使用了一种很直接的算法:

  1.查找路由字典的“controller”键。

  2.取得这个键的值,并附加字符串“Controller”,以得到控制器的类型名。

  3.用这个类型名查找Web API控制器。

  例如,如果路由字典中的键-值对为“controller”=“products”,那么控制器类型便为“ProductsController”。如果没有匹配类型,或有多个匹配,这个框架会给客户端返回一条错误。

对于步骤3,DefaultHttpControllerSelector使用IHttpControllerTypeResolver接口以获得Web API控制器类型的列表。 IHttpControllerTypeResolver的默认实现会返回所有符合以下条件的public类:

a:实现IHttpController的类。

b:是非抽象类。

c:名称以“Controller”结尾的类。

Action Selection

  选择了控制器之后,这个框架会通过调用IHttpActionSelector.SelectAction方法来选择动作。这个方法以HttpControllerContext为参数,并返回HttpActionDescriptor

这个默认实现是由ApiControllerActionSelector类提供的。为了选择一个动作,会查找以下方面:

  1.HTTP请求的方法。

  2.这个路由模板中的“action”占位符。

  3.控制器中动作的参数。

在查找选择算法之前,我们需要理解控制器动作的一些事情。

  控制器中的哪些方法被看成为是“动作”?当选择一个动作时,这个框架只考察控制器的public实例方法。而且,它会排除特殊名称的方法(构造器、事件、操作符、重载等等),以及集成自ApiController的类方法。

 

HTTP Methods

这个框架只会选择与请求的HTTP方法匹配的动作,确定如下:

  1.你可以用注解属性AcceptVerbs、HttpDelete、HttpGet、HttpHead、HttpOptions、HttpPatch、HttpPost、或HttpPut来指定HTTP方法。

  2.否则,如果控制器方法名称以“Get”、“Post”、“Put”、“Delete”、“Head”、“Options”、或“Patch”开头,那么根据这个约定,该Action将支持相应的HTTP方法。

  3.如果以上都不是,那么这个方法将支持Post。

Parameter Bindings.

  参数绑定是指Web API如何创建参数值。以下是参数绑定的默认规则:1.简单类型取自URI。2.复杂类型取自请求正文。

简单类型包括所有“.NET框架简单类型”,另外还有,DateTime、Decimal、Guid、String和TimeSpan。对于每一个动作,最多只有一个参数可以读取请求正文。

它也可以重写这种默认的绑定规则。See WebAPI Parameter binding under the hood

在这种背景下,动作选择算法如下:

1.创建该控制器中与HTTP请求方法匹配的所有动作的列表。

2.如果路由字典有“action”条目,移除与该条目值不匹配的动作。

3.试图将动作参数与该URI匹配,如下:

  a:针对每个动作,获得简单类型的参数列表,这是绑定得到URI参数的地方。该列表不包括可选参数。

  b:从这个列表中,试着在路由字典或是在URI查询字符串中,找到每个参数的匹配。匹配是与大小写无关的,且与参数顺序无关。

  c:选择这样的一个action,在列表中的每个参数在URI中有一个匹配。

  d:如果满足这些条件的动作不止一个,选用参数匹配最多的一个。

4.忽略用[NonAction]注解属性标注的动作。

 

第3步可能会让人困扰。其基本思想是,可以从URI、或请求体、或一个自定义绑定来获取参数值。对于来自URI的参数,我们希望确保URI在其路径(通过路由字典)或查询字符串中实际包含了一个用于此参数的值。

例如,考虑以下动作:

public void Get(int id)

其id参数绑定到URI。因此,这个动作只能匹配在路由字典或查询字符串中包含了“id”值的URI。

可选参数是一个例外,因为它们是可选的。对于可选参数,如果绑定不能通过URI获取它的值,是没关系的。

复杂类型是另一种原因的例外。一个复杂类型只能通过自定义绑定来绑定到URI。但是在这种情况下,这个框架不能提前知道是否这个参数被绑定到一个特殊的URI。为了查明情况,这个框架需要调用这个绑定。选择算法的目的是在调用绑定之前根据静态描述来选择一个动作。因此,复杂类型是属于匹配算法之外的。

动作选择之后,会调用所有参数绑定。

Summary:

1.动作必须匹配请求的HTTP方法。

2.动作名必须匹配路由字典中的“action”条目,如果有。

3.对于动作的各个参数,如果参数取自URI,那么该参数名必须在路由字典或URI查询字符串中能够被找到。(可选参数和复杂类型除外)。

4.试图匹配最多数目的参数。最佳匹配可能是一个无参数的方法。

Extended Example

看如下路由:

routes.MapHttpRoute( 
    name: "ApiRoot", 
    routeTemplate: "api/root/{id}", 
    defaults: new { controller = "products", id = RouteParameter.Optional } 
); 

routes.MapHttpRoute( 
    name: "DefaultApi", 
    routeTemplate: "api/{controller}/{id}", 
    defaults: new { id = RouteParameter.Optional } 
);

再看如下Contoller下的内容:

public class ProductsController : ApiController 
{ 
    public IEnumerable<Product> GetAll() {} 
    public Product GetById(int id, double version = 1.0) {} 
    [HttpGet] 
    public void FindProductsByName(string name) {} 
    public void Post(Product value) {} 
    public void Put(int id, Product value) {} 
}

 

 

HTTP请求:

http://localhost:34701/api/products/1?version=1.5&details=1

路由匹配:

该URI与名为“DefaultApi”路由匹配。路由字典包含以下条目:controller:"products",id:"1"。该路由字典并未包含查询字符串参数“version”和“details”,但这些将在动作选择期间考虑。

控制器选择:

根据路由字典中的“controller”条目,控制器类型是ProductsController。

动作选择:

这个HTTP请求是一个GET请求。支持Get的控制器动作是GetALL、GetById、FindProductsByName。这个路由字典不包含”action“条目,因此不需要匹配动作名称。

下一步,会试图匹配这些动作的参数名,只考查GET动作。

注意,不会考虑GetById的version参数,因为它是一个可选参数。

GetAll方法非常匹配。GetById方法也匹配,因为路由字典包含了“id”。FindProductsByName方法不匹配。

GetById方法是赢家,因为它匹配了一个参数,而GetAll无参数。该方法将以以下参数值被调用:id=1,version=1.5

注意,虽然version未被用于选择算法,但该参数值会取自URI查询字符串。

Extension Points

 Web API为路由过程的某些部分提供了扩展点。

要为以上任一接口提供自己的实现,可使用HttpConfiguration对象的Services集合:

var config = GlobalConfiguration.Configuration;
config.Services.Replace(typeof(IHttpControllerSelector), new MyControllerSelector(config));

总结

 这一篇好难懂,无奈之下多查了一下,就感觉肯定早有人翻译过了,还真是就在博客园就有,我之前咋就没发现呢http://www.cnblogs.com/r01cn/archive/2012/12/04/2801158.html,感觉大神翻译的真心赞,好好看就看懂了,为了提高自己阅读英语的水平,看一句英文,看一句翻译,然后自己再逐字敲一遍。这一篇下来真心累了。不过自己对Asp.Net MVC的路由机制也有了新的认识,不错。

参考原文链接http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-and-action-selection

 

目录
相关文章
|
7天前
|
开发框架 监控 前端开发
在 ASP.NET Core Web API 中使用操作筛选器统一处理通用操作
【9月更文挑战第27天】操作筛选器是ASP.NET Core MVC和Web API中的一种过滤器,可在操作方法执行前后运行代码,适用于日志记录、性能监控和验证等场景。通过实现`IActionFilter`接口的`OnActionExecuting`和`OnActionExecuted`方法,可以统一处理日志、验证及异常。创建并注册自定义筛选器类,能提升代码的可维护性和复用性。
|
7天前
|
开发框架 .NET 中间件
ASP.NET Core Web 开发浅谈
本文介绍ASP.NET Core,一个轻量级、开源的跨平台框架,专为构建高性能Web应用设计。通过简单步骤,你将学会创建首个Web应用。文章还深入探讨了路由配置、依赖注入及安全性配置等常见问题,并提供了实用示例代码以助于理解与避免错误,帮助开发者更好地掌握ASP.NET Core的核心概念。
21 3
|
12天前
|
开发框架 前端开发 .NET
VB.NET中如何利用ASP.NET进行Web开发
在VB.NET中利用ASP.NET进行Web开发是一个常见的做法,特别是在需要构建动态、交互式Web应用程序时。ASP.NET是一个由微软开发的开源Web应用程序框架,它允许开发者使用多种编程语言(包括VB.NET)来创建Web应用程序。
39 5
|
11天前
|
开发框架 JSON 缓存
震撼发布!Python Web开发框架下的RESTful API设计全攻略,让数据交互更自由!
在数字化浪潮推动下,RESTful API成为Web开发中不可或缺的部分。本文详细介绍了在Python环境下如何设计并实现高效、可扩展的RESTful API,涵盖框架选择、资源定义、HTTP方法应用及响应格式设计等内容,并提供了基于Flask的示例代码。此外,还讨论了版本控制、文档化、安全性和性能优化等最佳实践,帮助开发者实现更流畅的数据交互体验。
32 1
|
2月前
|
存储 消息中间件 前端开发
Web2py框架下的神秘力量:如何轻松集成第三方API,让你的应用不再孤单!
【8月更文挑战第31天】在开发现代Web应用时,常需集成第三方服务如支付网关、数据存储等。本文将指导你使用Web2py框架无缝接入第三方API。通过实例演示从注册获取API密钥、创建控制器、发送HTTP请求到处理响应的全过程。利用`requests`库与Web2py的内置功能,轻松实现API交互。文章详细介绍了如何编写RESTful控制器,处理API请求及响应,确保数据安全传输。通过本教程,你将学会如何高效整合第三方服务,拓展应用功能。欢迎留言交流心得与建议。
37 1
|
2月前
|
API 网络安全 数据库
Web2py框架如何颠覆传统的RESTful API开发?掌握这些技巧,让你的开发效率飞跃!
【8月更文挑战第31天】Web2py是一款全栈Python Web框架,适用于快速开发复杂交互的Web应用。本文将介绍如何使用Web2py创建RESTful API,包括设置新控制器、定义RESTful路由、处理数据库交互、确保API安全性、编写文档与使用Swagger、测试API以及部署时的注意事项。Web2py的高度抽象和易用性使其成为实现RESTful API的理想选择,帮助开发者专注于业务逻辑而非技术细节。
24 0
|
2月前
|
开发框架 监控 .NET
开发者的革新利器:ASP.NET Core实战指南,构建未来Web应用的高效之道
【8月更文挑战第28天】本文探讨了如何利用ASP.NET Core构建高效、可扩展的Web应用。ASP.NET Core是一个开源、跨平台的框架,具有依赖注入、配置管理等特性。文章详细介绍了项目结构规划、依赖注入配置、中间件使用及性能优化方法,并讨论了安全性、可扩展性以及容器化的重要性。通过这些技术要点,开发者能够快速构建出符合现代Web应用需求的应用程序。
35 0
|
2月前
|
API
【Azure API 管理】在 Azure API 管理中使用 OAuth 2.0 授权和 Azure AD 保护 Web API 后端,在请求中携带Token访问后报401的错误
【Azure API 管理】在 Azure API 管理中使用 OAuth 2.0 授权和 Azure AD 保护 Web API 后端,在请求中携带Token访问后报401的错误
|
2月前
|
开发框架 前端开发 .NET
ASP.NET MVC WebApi 接口返回 JOSN 日期格式化 date format
ASP.NET MVC WebApi 接口返回 JOSN 日期格式化 date format
36 0
|
2月前
|
存储 开发框架 .NET
ASP.NET Web Api 使用 EF 6,DateTime 字段如何取数据库服务器当前时间
ASP.NET Web Api 使用 EF 6,DateTime 字段如何取数据库服务器当前时间
下一篇
无影云桌面