1. 导言

路由系统是请求消息进入ASP.NET Web API消息处理管道的第一道屏障,其根本目的在于利用注册的路由对请求的URL进行解析以确定目标HTTPController和Action的名称,以及与目标Action方法某个参数进行绑定的路由变量。

WebService和WCF的协议都是soap协议,数据的序列化和反序列化都是soap的格式。而WebAPI是基于Http协议,请求和返回格式结果默认是 json格式,因此,比WCF更简单、更通用,比 WebService 更节省流量、更简洁。 Web API是在.NET Framework上构建RESTful应用程序的理想平台,为了更清楚弄懂WebAPI的路由配置,我们首先要了解HTTP协议和RESTful架构风格。

2. HTTP协议

HTTP协议(HyperText Transfer Protocol,超文本传输协议)是因特网上应用最为广泛的一种网络传输协议,所有的WWW文件都必须遵守这个标准。我们在这里紧列举和本文关系密切的HTTP请求方法和HTTP状态码。

2.1 HTTP请求方法

根据HTTP标准,HTTP请求可以使用多种请求方法。

HTTP1.0定义了三种请求方法: GET, POST 和 HEAD方法,HTTP1.1新增了五种请求方法:OPTIONS, PUT, DELETE, TRACE 和 CONNECT 方法,如下表所示:

序号 方法 描述
1 GET 请求指定的页面信息,并返回实体主体。
2 HEAD 类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头
3 POST 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。
4 PUT 从客户端向服务器传送的数据取代指定的文档的内容。
5 DELETE 请求服务器删除指定的页面。
6 CONNECT HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
7 OPTIONS 允许客户端查看服务器的性能。
8 TRACE 回显服务器收到的请求,主要用于测试或诊断。

2.2 HTTP状态码

当浏览者访问一个网页时,浏览者的浏览器会向网页所在服务器发出请求。当浏览器接收并显示网页前,此网页所在的服务器会返回一个包含HTTP状态码(HTTP Status Code)的信息头(server header)用以响应浏览器的请求。

常见的HTTP状态码如下表:

状态码 状态码英文名称 中文描述
200 OK 请求成功。一般用于GET与POST请求
301 Moved Permanently 永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替
404 Not Found 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面
500 Internal Server Error 服务器内部错误,无法完成请求

3. RESTful介绍

在介绍RESTful之前,我们需了解什么REST,他有那些特征,以及REST成熟度模型。

3.1 REST介绍

REST是Representational State Transfer的缩写,翻译为表象化状态转变或表述性状态转变,是Roy Fielding博士在2000年他的博士论文中提出来的一种软件架构风格,它包含了一个分布式超文本系统中对于组件、连接器和数据的约束。REST 是作为互联网自身架构的抽象而出现的,其关键在于所定义的架构上的各种约束。只有满足这些约束,才能称之为符合 REST 架构风格。

3.2 REST系统的特征

RESR系统包括6个特征,如下所示:

(1)客户端-服务器结构(Client-Server)

通过一个统一的接口来分开客户端和服务器,使得两者可以独立开发和演化。客户端的实现可以简化,而服务器可以更容易的满足可伸缩性的要求;

(2)无状态(Stateless)

在不同的客户端请求之间,服务器并不保存客户端相关的上下文状态信息。任何客户端发出的每个请求都包含了服务器处理该请求所需的全部信息;

(3)可缓存(Cachable)

客户端可以缓存服务器返回的响应结果。服务器可以定义响应结果的缓存设置。

(4)分层的系统(Layered System)

在分层的系统中,可能有中间服务器来处理安全策略和缓存等相关问题,以提高系统的可伸缩性。客户端并不需要了解中间的这些层次的细节。

(5)按需代码(Code-On-Demand,可选)

服务器可以通过传输可执行代码的方式来扩展或自定义客户端的行为。这是一个可选的约束。

(6)统一接口(Uniform Interface)

该约束是 REST 服务的基础,是客户端和服务器之间的桥梁。该约束又包含下面 4 个子约束。

  • 资源标识符:每个资源都有各自的标识符。客户端在请求时需要指定该标识符。在 REST 服务中,该标识符通常是 URI。客户端所获取的是资源的表达(representation),通常使用 XML 或 JSON 格式。
  • 通过资源的表达来操纵资源:客户端根据所得到的资源的表达中包含的信息来了解如何操纵资源,比如对资源进行修改或删除。
  • 自描述的消息:每条消息都包含足够的信息来描述如何处理该消息。
  • 超媒体作为应用状态的引擎(HATEOAS):客户端通过服务器提供的超媒体内容中动态提供的动作来进行状态转换。

3.3 REST成熟度模型

Richardson 提出的 REST 成熟度模型。该模型把 REST 服务按照成熟度划分成 4 个层次,我们常用到的就是Level1和Level2,如下图所:

具体说明如下:

Level 0:Web 服务只是使用 HTTP 作为传输方式,实际上只是远程方法调用(RPC)的一种具体形式。SOAP 和 XML-RPC 都属于此类。

Level 1:Web 服务引入了资源的概念。每个资源有对应的标识符和表达。

Level 2:Web 服务使用不同的 HTTP 方法来进行不同的操作,并且使用 HTTP 状态码来表示不同的结果。如 HTTP GET 方法来获取资源,HTTP DELETE 方法来删除资源。

Level 3:Web 服务使用 HATEOAS。在资源的表达中包含了链接信息。客户端可以根据链接来发现可以执行的动作。例如,客户端通过订单资源中包含的链接取消某一订单,GET 请求被发送去获取该订单。HATEOAS 的优点包括无需在客户端代码中写入硬链接的 URL。此外,由于资源信息中包含可允许操作的链接,客户端无需猜测在资源的当前状态下执行何种操作。

3.4 RESTful

RESTful是一种常见的REST应用,是遵循REST风格的web服务,REST式的web服务是一种ROA(面向资源的架构)。

RESTful资源操作如下表:

http方法 资源操作 幂等 安全
GET SELECT
POST INSERT
PUT UPDATE
DELETE DELETE

注:幂等性:对同一REST接口的多次访问,得到的资源状态是相同的;安全性:对该REST接口访问,不会使服务器端资源的状态发生改变。

RESTful URL请求格式与传统请求格式比较如下表所示:

传统URL请求格式 RESTFul请求格式 描述
http:/localhost/user/query/1  GET  http:/localhost/user/1  GET 根据用户id查询用户数据
http:/localhost/user/save      POST http:/localhost/user     POST 新增用户
http:/localhost/user/update   POST  http:/localhost/user     PUT 修改用户信息
http:/localhost/user/delete    GET/POST http:/localhost/user     DELETE 删除用户信息

4.Web API路由

路由的目的是用于解析请求的URL来确定Controller和Action。Web API默认路由是通过http的方法(get/post/put/delete)去匹配对应的action,也就是说webapi的默认路由并不需要指定action的名称,当然,WebApi也支持MVC里面的路由机制,但RestFul风格的服务要求请求的url里面不能包含action,所以,在WebApi里面是并不提倡使用MVC路由机制的。下边通过例子介绍Web API路由原理以及使用。

4.1新建空的Web API应用程序

上篇博客介绍了手动搭建基本框架,这次我们通过VS2017提供的模板,新建空的WebAPI应用程序MyWebAPI2,构建过程中仅勾选Web API,如下图所示。

创建完成,应用程序的目录结构如下图所示。

4.2默认路由

App_Start文件夹下WebApiConfig.cs类用于注册Web API路由,默认路由代码如下:

public static void Register(HttpConfiguration config)
{
//默认路由
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}

在Models文件夹增加一个Student类,代码如下:

public class Student
{
public string Id { get; set; }
public string Name { get; set; }
public string Sex { get; set; }
public int Age { get; set; }
public string Dept { get; set; }
}

在Controllers文件夹中添加一个Web API控制类(v2.1),命名为StudentController,并修改相关代码,如下所示:

 public class StudentController : ApiController
{
private static List<Student> studentList = new List<Student>()
{
new Student() {Id = "", Name = "张三", Sex = "男", Age = , Dept = "软件学院"},
new Student() {Id = "", Name = "李丽", Sex = "女", Age = , Dept = "资环学院"}
}; [HttpGet]
public IEnumerable<Student> Get()
{
return studentList;
} [HttpGet]
public Student Get(string id)
{
List<Student> tempList = studentList.Where(p => p.Id == id).ToList();
return tempList.Count==?tempList.First():null ;
} [HttpPost]
public bool Post([FromBody]Student student)
{
if (student == null) return false;
if (studentList.Where(p=>p.Id==student.Id).ToList().Count>) return false;
studentList.Add(student);
return true;
} [HttpPut]
public bool Put(string id, [FromBody]Student student)
{
if (student == null) return false;
List<Student> tempList = studentList.Where(p => p.Id == id).ToList();
if (tempList.Count == ) return false;
Student originStudent = tempList[];
originStudent.Name = student.Name;
originStudent.Sex = student.Sex;
originStudent.Age = student.Age;
originStudent.Dept = student.Dept;
return true;
}
[HttpDelete]
public bool Delete(string id)
{
List<Student> tempList = studentList.Where(p => p.Id == id).ToList();
if (tempList.Count == ) return false;
studentList.Remove(tempList[]);
return true;
}
}

在实际项目中,增删改查这些操作都是和数据库打交道的,这里为了演示具体实现,用一个静态数组存储数据。运行程序,我们采用Fiddler工具进行测试调用。

测试一:调用Get()方法

功能说明:通过路由解析StudentController中的Get()Action,获取所有学生列表。

URL:http://localhost:52317/api/student;HTTP方法:GET。如下图所示:

测试结果:HTTP状态码为200,获取的JSON数据如下所示:

测试二:调用Get(string id)方法

功能说明:通过路由解析StudentController中的Get(string id)Action,根据学号获取某个学生信息。

URL:http://localhost:52317/api/student/002;HTTP方法:GET

测试结果:HTTP状态码为200,获取的JSON数据如下所示:

测试三:调用Post([FromBody]Student student)方法

功能说明:通过路由解析StudentController中的Post([FromBody]Student student)Action,插入一条数据,其中参数前添加[FromBody]是指该参数不是从URL中获取,而是在RequestBody中获取。

URL:http://localhost:52317/api/student;HTTP方法:POST。在RequestBody输入Json格式的数据,如下图所示:

测试结果:HTTP状态码为200,返回的数据TRUE。重复测试一,获取所有学生列表如下图所示。

测试四:调用Put(string id, [FromBody]Student student)方法

功能说明:通过路由解析StudentController中的Put(string id, [FromBody]Student student)Action,实现通过学号更新信息,其中学号id是在Url中获取。

URL:http://localhost:52317/api/student/002;HTTP方法:PUT

测试结果:HTTP状态码为200,返回的数据TRUE。

测试五:调用Delete(string id)方法

功能说明:通过路由解析StudentController中的Delete(string id)Action,删除某学生信息,其中学号id是在Url中获取。

URL:http://localhost:52317/api/student/002;HTTP方法:DELETE

测试结果:HTTP状态码为200,返回的数据TRUE。

总结:通过上边测试,我们可以到URL中没有用到Action,默认路由就是通过参数和HTTP方法匹配Controller中的Action。

4.3自定义路由

在实际项目中,如果http请求的类型相同,且请求参数相同(如Get),这个时候按照默认路由肯定会出问题,具体出现什么问题,我们在这做个测试:

在StudentController中添加一个Action,用于查询某个学院的所有同学,代码如下:

        [HttpGet]
public IEnumerable<Student> GetByDept(string id)
{
List<Student> tempList = studentList.Where(p => p.Dept == id).ToList();
return tempList;
}

这时,运行程序,输入URL:http://localhost:52317/api/student/资环学院;HTTP方法:GET。测试结果发现返回的结果null,跟踪测试代码发现该URL调用的Get(string id)这个Action。

那么问题就来了,怎么才能调用这个Action呢?其中有两种方法一种是自定义路由,就像MVC那样在模板中增加Action,另一种为通过Web API路由特性实现。

在App_Start文件夹下WebApiConfig.cs类中添加ActionAPI路由模板,代码如下:

public static void Register(HttpConfiguration config)
{
//默认路由
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
//自定义路由
config.Routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}

运行程序,输入URL:http://localhost:52317/api/student/GetByDept/资环学院;HTTP方法:GET。运行结果如下:

注:若出现中文乱码,解决途径请参考Fiddler抓包中文乱码问题

由此可知通过自定义路由可以解决该问题,但是不符合RESTful风格,所有不提倡使用该方法。

4.4特性路由

默认路由解决不了的访问,可以通过Web API的路由特性解决。

启动路由特性:在App_Start文件夹下WebApiConfig.cs类中启用特性路由,代码如下:

public static void Register(HttpConfiguration config)
{
//启用Web API特性路由
config.MapHttpAttributeRoutes(); //默认路由
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
//自定义路由
config.Routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}

修改StudentController中GetByDept代码如下:

        [Route("student/GetByDept/{dept}")]
[HttpGet]
public IEnumerable<Student> GetByDept(string dept)
{
List<Student> tempList = studentList.Where(p => p.Dept == dept).ToList();
return tempList;
}

运行程序,输入URL:http://localhost:52317/student/GetByDept/软件学院;HTTP方法:GET。运行结果如下:

通过此例,可以看到Web API特性路由非常灵活方便,具体使用要结合实际项目灵活运用。

5. 总结

本文在开始部分介绍了HTTP协议及RESTful架构风格,让我们更深入的了解Web API的设计初衷,又通过实际的例子(文中的代码及结果均通过了测试),让我们掌握了路由配置的各种方法。文中若有不足之处,还望海涵,博文写作不易希望多多支持,后续会更新更多内容,感兴趣的朋友可以加关注,欢迎留言交流!

ASP.NET Web API 2系列(二):灵活多样的路由配置的更多相关文章

  1. ASP.NET Web API 2系列(三):查看WebAPI接口的详细说明及测试接口

    引言 前边两篇博客介绍了Web API的基本框架以及路由配置,这篇博客主要解决在前后端分离项目中,为前端人员提供详细接口说明的问题,主要是通过修改WebApi HelpPage相关代码和添加WebAp ...

  2. ASP.NET Web API实践系列04,通过Route等特性设置路由

    ASP.NET Web API路由,简单来说,就是把客户端请求映射到对应的Action上的过程.在"ASP.NET Web API实践系列03,路由模版, 路由惯例, 路由设置"一 ...

  3. ASP.NET Web API 2系列(四):基于JWT的token身份认证方案

    1.引言 通过前边的系列教程,我们可以掌握WebAPI的初步运用,但是此时的API接口任何人都可以访问,这显然不是我们想要的,这时就需要控制对它的访问,也就是WebAPI的权限验证.验证方式非常多,本 ...

  4. ASP.NET Web API实践系列07,获取数据, 使用Ninject实现依赖倒置,使用Knockout实现页面元素和视图模型的双向绑定

    本篇接着上一篇"ASP.NET Web API实践系列06, 在ASP.NET MVC 4 基础上增加使用ASP.NET WEB API",尝试获取数据. 在Models文件夹下创 ...

  5. ASP.NET Web API实践系列05,消息处理管道

    ASP.NET Web API的消息处理管道可以理解为请求到达Controller之前.Controller返回响应之后的处理机制.之所以需要了解消息处理管道,是因为我们可以借助它来实现对请求和响应的 ...

  6. ASP.NET Web API WebHost宿主环境中管道、路由

    ASP.NET Web API WebHost宿主环境中管道.路由 前言 上篇中说到ASP.NET Web API框架在SelfHost环境中管道.路由的一个形态,本篇就来说明一下在WebHost环境 ...

  7. ASP.NET Web API Selfhost宿主环境中管道、路由

    ASP.NET Web API Selfhost宿主环境中管道.路由 前言 前面的几个篇幅对Web API中的路由和管道进行了简单的介绍并没有详细的去说明一些什么,然而ASP.NET Web API这 ...

  8. ASP.NET Web API 2系列(一):初识Web API及手动搭建基本框架

    1.导言 随着Web技术的发展,现在各种框架,前端的,后端的,数不胜数.全栈工程师的压力越来越大. PC端,pad端,移动端App(安卓/IOS)的发展,使得前后端一体的开发模式十分笨重.因此,前后端 ...

  9. ASP.NET Web API实践系列09,在Fiddler和控制台中模拟GET和POST请求

    ASP.NET Web API本质是由一个进程托管的一组类,需要宿主,这个宿主可以是ASP.NET应用程序,可以是MVC项目,可以是控制台应用程序,也可以是自己定制的宿主. 在VS2012中创建一个& ...

随机推荐

  1. codeforces 361 D. Levko and Array(dp+二分)

    题目链接:http://codeforces.com/contest/361/problem/D 题意:最多可以修改K次数字,每次修改一个数字变成任意值,C=max(a[i+1]-a[i]):求操作之 ...

  2. Springboot基于enable模块驱动

    enable作为模块驱动在Spring Farmework.Spring Boot.Spring Cloud使用,都是通过注解的形式以@enable作为前缀,一些常用注解如 | 框架 | 注解 | 模 ...

  3. 【LeetCode】334#递增的三元子序列

    题目描述 给定一个未排序的数组,判断这个数组中是否存在长度为 3 的递增子序列. 数学表达式如下: 如果存在这样的 i, j, k, 且满足 0 ≤ i < j < k ≤ n-1, 使得 ...

  4. (转)为什么HashMap中链表长度超过8会转换成红黑树

    原博地址:https://blog.csdn.net/xingfei_work/article/details/79637878 HashMap在jdk1.8之后引入了红黑树的概念,表示若桶中链表元素 ...

  5. Graph and Chart Study

    1.选择主题 “Themes”,以"Graph"——“preset7” 为例: 2.选择“Canvas”——“GraphChart”预制体,1.Set data categorie ...

  6. Linux防火墙管理

    1.临时关闭防火墙 systemctl stop firewalld 2.查看防火墙运行状态 firewall-cmd --state 3.开启防火墙 systemctl start firewall ...

  7. 关于解决web编码问题的总结

    网页的编码问题,一般分为两个方面 1 是网页本身的编码格式, 一般不同的操作系统网页文件存取的编码是不一样的, 但一般来说, 新建网页文件一般都和IDE有关,因为我们平时我是使用编辑工具新建网页文件. ...

  8. Android mmap 文件映射到内存介绍

    本文链接: Android mmap 文件映射到内存介绍 Android开发中,我们可能需要记录一些文件.例如记录log文件.如果使用流来写文件,频繁操作文件io可能会引起性能问题. 为了降低写文件的 ...

  9. Java第三次作业第一题

    1.[请复制本程序,作为java程序代码,进行编译,补充填写缺失代码部分,并实现题目要求功能,从而获得空白填写所需的内容.] 编写无限计时程序,从0:1开始计时,一直循环计时,计时到60秒,变为1:0 ...

  10. Mysql高手系列 - 第13篇:细说NULL导致的神坑,让人防不胜防

    这是Mysql系列第13篇. 环境:mysql5.7.25,cmd命令中进行演示. 当数据的值为NULL的时候,可能出现各种意想不到的效果,让人防不胜防,我们来看看NULL导致的各种神坑,如何避免? ...