Asp.Net Web API 导航html
Asp.Net Web API第一课——入门http://www.cnblogs.com/aehyok/p/3432158.htmlgit
Asp.Net Web API第二课——CRUD操做http://www.cnblogs.com/aehyok/p/3434578.htmlweb
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.htmlapi
前言框架
本文描述ASP.NET Web API如何把一个HTTP请求路由到控制器的一个特定的Action上。关于路由的整体概述能够参见上一篇教程 http://www.cnblogs.com/aehyok/p/3442051.html。这篇文章主要来学习路由过程的细节。若是你建立了一个Web API项目,发现有一些请求没有按照你指望的方式被路由,但愿这篇文章将对你有所帮助。asp.net
本文主要分为三个阶段:学习
1.匹配URI到一个Route Template。ui
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}”。
若是你提供默认值,那么这个路由将匹配缺乏这些片断的URI。例如:
routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{category}", defaults: new { category = "all" } );
这个URI“http://localhost/api/products”与这个路由是匹配的。“{category}”片断被赋成了默认值“all”。
若是这个框架发现了一个匹配的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