Web API 路由机制分析
- Web API项目的路由机制是在App_Start文件下自动生成一个WebApiConfig.cs文件
1 public static class WebApiConfig 2 { 3 public static void Register(HttpConfiguration config){ 4 // Web API 路由 5 config.MapHttpAttributeRoutes();//启动特性路由 6 config.Routes.MapHttpRoute( 7 name: "DefaultApi", 8 routeTemplate: "api/{controller}/{id}", 9 defaults: new { id = RouteParameter.Optional } 10 ); 11 } 12 } 13 //下面是方法参数 14 public static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name, string routeTemplate, object defaults, object constraints);
- MapHttpRoute()方法参数
- name:路由的名称,保证不能重复
- routeTemplate:路由模板,比如"api/{controller}/{id}"这个路由,"api"是固定部分,区别一下这个是Web API项目;"{controller}"这个是控制器的占位符,在真正URL中这里是控制器名称;"{id}"是参数的占位符
- defaults:"new { id = RouteParameter.Optional }"这句话表示id这个参数是可选的,还可以设置controller="TestRoute",这样如果路径是http://localhost:61218/api,也可以访问到
- constraints:表示路由约束,一般是一个约束路由模板的正则表达式,比如设置constraints: new { id = @"\d+" } 表示id参数为一个到多个整数,访问http://localhost:61218/api/TestRoute/a返回404报错
1 public class TestRouteController : ApiController 2 { 3 [HttpGet]//http://localhost:61218/api/TestRoute 4 public object GetAll(){ 5 return "Success"; 6 } 7 [HttpGet]//http://localhost:61218/api/TestRoute/1 8 public object GetById(int id){ 9 return "Success" + id; 10 } 11 }
- WebApiConfig.cs文件中自定义路由模板
1 config.Routes.MapHttpRoute( 2 name: "ActionApi", 3 routeTemplate: "actionapi/{controller}/{action}/{id}", 4 defaults: new { id = RouteParameter.Optional } 5 ); 6 config.Routes.MapHttpRoute( 7 name: "TestApi", 8 routeTemplate: "testapi/{controller}/{ordertype}/{id}", 9 defaults: new { ordertype = "orderby", id = RouteParameter.Optional } 10 );
- 访问GetAll()的路径:http://localhost:61218/actionapi/TestRoute/GetAll,http://localhost:61218/testapi/TestRoute/orderby
- 访问GetById()的路径:http://localhost:61218/actionapi/TestRoute/GetById/2,http://localhost:61218/testapi/TestRoute/orderby/2
- 同时可以在方法上面使用ActionName特性修改action的名称,http://localhost:61218/actionapi/TestRoute/GetById/2就无法访问该方法,只有改成http://localhost:61218/actionapi/TestRoute/TestActionName/2才能访问,
1 [ActionName("TestActionName")] 2 [HttpGet] 3 public object GetById(int id){ 4 return "Success" + id; 5 }
- 路由请求过程
- Web API服务启动之后,会执行全局配置文件Global.asax.cs中的Application_Start方法,会通过参数委托去执行WebApiConfig.cs文件中Register方法,将所有配置的路由信息添加到HttpRouteCollection对象中
- 当发送请求Web API服务器的时候,请求会首先被UrlRoutingModule监听组件截获,然后将截获的请求在Routes路由集合中匹配到对于的路由模板(如果匹配不到,则返回404),得到对于的IHttpRoute对象
- 将IHttpRoute对象交给当前请求的上下文对象RequestContext处理,根据IHttpRoute对象里面的url匹配到对应的控制器(根据DefaultHttpControllerSelector类的SelectController()方法,该类继承于IHttpControllerSelector接口)
- 如果路由模板中配置了{action},则直接就能从url中找到action名称匹配方法,反之没有配置,则首先根据http请求的类型(get/post/put/delete,可以通过特性进行设置)和参数找到对应的action
1 //该方法支持两种不同的请求,通过AcceptVerbs特性支持多种请求 2 [AcceptVerbs("GET", "POST")] 3 public IHttpActionResult GetById(int id){ 4 return Ok<string>("Success" + id ); 5 }
- 特性路由
- WebApiConfig.cs的Register()方法中config.MapHttpAttributeRoutes()启动特性路由
- Route特性:设置每个方法的访问路径,还可以使用"{}"占位符传递参数,同时可以使用约束和默认值(比如{id:int=3})
- RoutePrefix特性:设置路由前缀,比如下面的url前缀都是api/TestRoute2
1 [RoutePrefix("api/TestRoute2")] 2 public class TestRoute2Controller : ApiController 3 { 4 // [Route("~/")]//无论加不加前缀都可以通过 / 访问该页面 5 [Route("")] 6 [HttpGet]//http://localhost:61218/api/TestRoute2 7 public IHttpActionResult GetAll(){ 8 return Ok<string>("Success"); 9 } 10 [Route("{id:int=3}/OrderDetailById")]//约束int类型,且默认值为3 11 [HttpGet]//http://localhost:61218/api/TestRoute2/2/OrderDetailById 12 public IHttpActionResult GetById(int id){ 13 return Ok<string>("Success" + id ); 14 } 15 [Route("{no}/OrderDetailByNo")] 16 [HttpGet]//http://localhost:61218/api/TestRoute2/aa/OrderDetailByNo 17 public IHttpActionResult GetByNO(string no){ 18 return Ok<string>("Success" + no); 19 } 20 [Route("{name}/OrderDetailByName")] 21 [HttpGet]//http://localhost:61218/api/TestRoute2/cc/OrderDetailByName 22 public IHttpActionResult GetByName(string name){ 23 return Ok<string>("Success" + name); 24 } 25 [Route("postdata")] 26 [HttpPost] 27 public HttpResponseMessage PostData(int id){ 28 return Request.CreateResponse(); 29 } 30 [Route("Test/AttrRoute")] 31 [HttpPost] 32 public HttpResponseMessage SavaData(ORDER order){ 33 return Request.CreateResponse(); 34 } 35 }
- PostData()和SavaData()的post请求
1 $http.post("http://localhost:61218/api/TestRoute2/postdata?id=1").then(res => {}, () => {}) 2 $http.post("http://localhost:61218/api/TestRoute2/Test/AttrRoute",{data:{ID: 2, NO:"aaa"}}).then(res => {}, () => {})