Asp.Net Web API(三)

简介: Routing Tables路由表    在Asp.Net Web API中,一个控制器就是一个处理HTTP请求的类,控制器的public方法就被叫做action方法或简单的Action。当Web API接收到一个请求的时候,它将这个请求路由到一个Action。

Routing Tables路由表

    在Asp.Net Web API中,一个控制器就是一个处理HTTP请求的类,控制器的public方法就被叫做action方法或简单的Action。当Web API接收到一个请求的时候,它将这个请求路由到一个Action。

        注意:Web API的路由与Asp.Net MVC的路由是非常相似的。主要区别就是Web API使用的是HTTP方法,而不是URI路径来选择Action

   为了确定哪个Action被调用,这个框架使用了一个注册表。Visual Studio的Web API的项目模板会创建一个默认路由:

1   config.Routes.MapHttpRoute(
2                 name: "DefaultApi",
3                 routeTemplate: "api/{controller}/{id}",
4                 defaults: new { id = RouteParameter.Optional }
5 );

这个路由是在WebApiConfig文件中定义的,该文件位于App_Start目录

  当Web API框架接收到一个HTTP请求时,它会试图根据路由表中的一个路由模板来匹配其URI。如果无路由匹配,客户端会接收到一个404(未找到)错误。例如,以下URI与这个默认路由的匹配

  • /api/product
  • /api/product/1
  • /api/product?category=category

然而,以下URI就不匹配,因为它缺少“api”字段

  • /product/1     

        注意:在路由中使用“api”的原因是为了避免与ASP.NET MVC的路由冲突。通过这种方式,可以用“/product”进入一个控制器,而“/api/product”进入一个Web API控制器。当然,如果你不喜欢这种约定,也可以修改这个默认路由表。

     一旦一个匹配的路由被发现,Web API便会选择相应的Controller和Action。

         1.为了找到Controller,Web API会把“控制器”加到{Controller}变量的值

         2.为了找到Action,Web API会查找HTTP方法,然后寻找一个名称以HTTP方法名开头的方法。例如:对于Get请求,Web API会查找一个以“Get..”开头的Action,这种约定只应用于GET,POST,PUT,DELETE方法,通过在Controller上使用attribute,你可以启动其它的HTTP方法

         3.路由模板中其它的占位变量;例如{id},将会被映射成Action的参数。

Routing Variations路由变化

      HTTP方法

      替代使用HTTP方法的命名约定,你可以明确的为一个Action指定HTTP方法,通过以HttpGet,HttpPost,HttpPut或者HttpDelete属性来对Action方法进行修身

      在下列示例中,FindProduct方法被映射到GET请求

1 [HttpGet]
2 public Product FindProduct(int id)
3 {
4    return repository.Get(id);
5 }

使用上面代码时需要先注释上面写的GetProduct(int id);

因为如果不注释 Web API会匹配到请求匹配的多个操作错误

Web API允许一个Action对应多个HTTP方法;

 1 [AcceptVerbs("GET","POST","HEAD")]
 2 public Product FindProduct(int id)
 3 {
 4     return repository.Get(id);
 5 }
 6 [AcceptVerbs("MKCOL")]
 7 public void MakeCollection()
 8 {
 9 
10 }

    第一个方法:指示该Action接收HTTP的GET,POST和HEAD方法。

    第二个方法:WebDAV方法,(基于Web的分布式著作与版本控制的HTTP方法,是一个扩展的HTTP方法,MKCOL时隶属于WebDAV的一个方法,它在URI指定的位置创建集合)

通过Action名称路由

   在默认的路由模板中,这个Web API使用HTTP方法去选择Action。然而,你也可以在URI中创建包含Action名的路由

1 config.Routes.MapHttpRoute(
2           name: "DefaultApi",
3           routeTemplate: "api/{controller}/{Action}/{id}",
4           defaults: new { id = RouteParameter.Optional }
5 );

在这个路由模板中,{action}参数命名了控制器的Action方法。采用这种风格,需要使用注解属性来指明所允许的HTTP方法。例如,假设你的控制器已有以下方法:

1 [HttpGet] 
2 public string Details(int id); 

  在这中情况下,一个GET请求“api/Product/Details/1”将会映射到这个Detail方法。这种风格的路由类似于Asp.Net MVC,而且可能与RPC式的API接近。

  你也可以通过使用ActionName注解属性来覆盖动作名。在以下例子中,有两个Action映射到"api/product/thumbnail/id"。一个支持GET,一个支持POST

1 [HttpGet]
2 [ActionName("Thumbnail")]
3 public HttpResponseMessage GetThumbnailImage(int id);
4 [HttpPost]
5 [ActionName("Thumbnail")]
6 public void AddThumbnailImage(int id); 

NonActions

为了防止一个方法被当作Action所请求,可以使用NonAction注解属性。它对框架发送信号:这个方法不是以一个Action,即使它可能与路由规则匹配

1 [NonAction]
2 public void IsNoAction();

Route Templates

   路由模板看起来类似一个URI路径,但它可以具有占位符,并用{}来指示:

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

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

defaults: new { category = "all" }

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

constraints: new { id = @"\d+" }   // 只有在“id”是一个或多个数字时才匹配

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

 

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

   这个有两个特殊的占位符:“{Controller}”和“{Action}”。

       {Controller}提供控制器名

       {Action} 提供动作名。在Web API中,通常的约定是忽略{Action}的。

 

Defaults(默认值)

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

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

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

 Route Dictionary(路由字段)

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

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

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

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

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

 

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

1 routes.MapHttpRoute( 
2     name: "Root", 
3     routeTemplate: "api/root/{id}", 
4     defaults: new { controller = "product", id = RouteParameter.Optional } 
5 );

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

Selecting a Controller

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

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

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

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

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

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

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

  1.  实现IHttpController的类
  2. 是非抽象类
  3. 名称以”Contoller“结尾的类

Action Selection

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

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

  1. HTTP请求的方法
  2. 这个路由模板的action占位符
  3. 控制器中Action的参数

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

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

HTTP Methods

    Web API框架只会选择与请求的HTTP方法匹配的Action,确定如下

  1. 你可以用注解属性AcceptVerbs,HttpDelete,HttpGet,HttpPost,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。对于每一个Action,最多只有一个参数可以读取请求正文。

   在这种背景下,Action选择算法如下

  1. 创建该控制器中与HTTP请求方法匹配的所有Action的列表
  2. 如果路由字典有Action条目,移除与该条目值不匹配的Action
  3. 试图将Action参数与该URI匹配,如下       

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

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

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

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

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

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

   例如,考虑以下Action

public void Get(int id)

   其id绑定到URI。因此,这个Action只能匹配在路由字典或查询字符串包含了id值的URI

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

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

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

Summary:

  1.  Action必须匹配请求的HTTP方法。
  2. Action名必须匹配路由字典中的Action条目,如果有的话。
  3. 对于Action的各个参数,如果参数来自URI,那么该参数名必须在路由字典或URI查询字符串中能够被找到(可选参数和复杂参数类型除外)
  4. 试图匹配最多数目的参数。最佳匹配可能是一个无参数的方法。

Extended Points

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

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

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

 

         

相关文章
|
17天前
|
存储 消息中间件 前端开发
Web2py框架下的神秘力量:如何轻松集成第三方API,让你的应用不再孤单!
【8月更文挑战第31天】在开发现代Web应用时,常需集成第三方服务如支付网关、数据存储等。本文将指导你使用Web2py框架无缝接入第三方API。通过实例演示从注册获取API密钥、创建控制器、发送HTTP请求到处理响应的全过程。利用`requests`库与Web2py的内置功能,轻松实现API交互。文章详细介绍了如何编写RESTful控制器,处理API请求及响应,确保数据安全传输。通过本教程,你将学会如何高效整合第三方服务,拓展应用功能。欢迎留言交流心得与建议。
28 1
|
27天前
|
监控 前端开发 Serverless
现代化 Web 应用构建问题之观测站点的PV、UV和API异常等指标如何解决
现代化 Web 应用构建问题之观测站点的PV、UV和API异常等指标如何解决
28 2
|
17天前
|
API C# 开发框架
WPF与Web服务集成大揭秘:手把手教你调用RESTful API,客户端与服务器端优劣对比全解析!
【8月更文挑战第31天】在现代软件开发中,WPF 和 Web 服务各具特色。WPF 以其出色的界面展示能力受到欢迎,而 Web 服务则凭借跨平台和易维护性在互联网应用中占有一席之地。本文探讨了 WPF 如何通过 HttpClient 类调用 RESTful API,并展示了基于 ASP.NET Core 的 Web 服务如何实现同样的功能。通过对比分析,揭示了两者各自的优缺点:WPF 客户端直接处理数据,减轻服务器负担,但需处理网络异常;Web 服务则能利用服务器端功能如缓存和权限验证,但可能增加服务器负载。希望本文能帮助开发者根据具体需求选择合适的技术方案。
52 0
|
17天前
|
API 网络安全 数据库
Web2py框架如何颠覆传统的RESTful API开发?掌握这些技巧,让你的开发效率飞跃!
【8月更文挑战第31天】Web2py是一款全栈Python Web框架,适用于快速开发复杂交互的Web应用。本文将介绍如何使用Web2py创建RESTful API,包括设置新控制器、定义RESTful路由、处理数据库交互、确保API安全性、编写文档与使用Swagger、测试API以及部署时的注意事项。Web2py的高度抽象和易用性使其成为实现RESTful API的理想选择,帮助开发者专注于业务逻辑而非技术细节。
21 0
|
20天前
|
开发框架 监控 .NET
开发者的革新利器:ASP.NET Core实战指南,构建未来Web应用的高效之道
【8月更文挑战第28天】本文探讨了如何利用ASP.NET Core构建高效、可扩展的Web应用。ASP.NET Core是一个开源、跨平台的框架,具有依赖注入、配置管理等特性。文章详细介绍了项目结构规划、依赖注入配置、中间件使用及性能优化方法,并讨论了安全性、可扩展性以及容器化的重要性。通过这些技术要点,开发者能够快速构建出符合现代Web应用需求的应用程序。
30 0
|
24天前
|
移动开发 数据挖掘 API
HTML5 中 Web Workers API 的用法
【8月更文挑战第24天】
33 0
|
24天前
|
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的错误
|
1月前
|
开发框架 前端开发 .NET
ASP.NET MVC WebApi 接口返回 JOSN 日期格式化 date format
ASP.NET MVC WebApi 接口返回 JOSN 日期格式化 date format
30 0
|
1月前
|
存储 开发框架 .NET
ASP.NET Web Api 使用 EF 6,DateTime 字段如何取数据库服务器当前时间
ASP.NET Web Api 使用 EF 6,DateTime 字段如何取数据库服务器当前时间
|
1月前
|
开发框架 .NET API
如何在 ASP.NET Core Web Api 项目中应用 NLog 写日志?
如何在 ASP.NET Core Web Api 项目中应用 NLog 写日志?