初识ASP.NET CORE Web Api

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace AspTest.Controllers {
[Route("api/[controller]")]
[ApiController]
public class TestController : ControllerBase {
[HttpGet]
public UserInfoRequest UserInfo() {
var UserInfo = new UserInfoRequest();
UserInfo.Email = "abc@123.com";
UserInfo.Name = "Test";
UserInfo.Password = "password";
return UserInfo;
}
[HttpPost]
public string UserInfoRequery(UserInfoRequest userInfo) {
Console.WriteLine(userInfo.Name);
Console.WriteLine(userInfo.Email);
return "ok";
}
}
}

Route特性内为访问路径。
web api比mvc少了视图,它的控制器依然以xxxController命名并且控制器类被[ApiController修饰],其中xxx表示控制器的名字,它需要继承ControllerBase,当浏览器访问/xxx路径时默认发起Get请求。
[HttpGet]、[HttpPost]用于修饰方法,该方法的返回值为http请求的响应内容(默认JSON)。

风格

web api风格有两种,一种是面向过程(RPC),一种是面向REST。

RPC:

通过“控制器/操作方法”(有点像mvc)的形式把服务器端的代码当成方法去调用。把http当成传输数据的通道,不关心http谓词,通过QueryString、请求报文体给服务器传递数据,状态码。比如:/Person/GetAll、/Person/GetById?id=8

REST:

按照http语义来使用http协议。
URL用于资源的定位:/user/888、/user/888/orders
http谓词有GET POST PUT DELETE PATCH等
DELETE PUT GET是幂等的
服务器端通过状态码来反应资源获取结果如404 403 201

REST的优点

可以对GET、PUT、DELETE请求进行重试;
可以用GET请求做缓存;
通过HTTP状态码反映服务器端的处理结果,统一错误处理机制
网关等可以分析请求处理结果;

REST的不足

很难清晰地进行资源的划分;
系统的进化可能会改变幂等;
有些环节会篡改非200响应码的响应报文;
有的客户端不支持PUT、DELETE

传递数据

方式:
URL、QueryString、请求报文体(不支持Get、Delete)

RPC风格请求数据传递

控制器上[Route(“[controller]/[action]”)]表示通过控制器名和方法名进行定位
强制要求控制器中不同的操作用不同的方法名
把[HttpGet]、[HttpPost]等添加到对应操作方法上
注意:如果控制器中存在一个没有添加[HttpGet]、[HttpPost]等的public方法,swagger就会报错,可以用[ApiExploreSetting(IgnoreApi = true)]
action方法支持方法重载,GET和POST可以使用同名的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
namespace AspTest.Controllers {
[Route("api/[controller]/[action]")]
[ApiController]
public class StudentController : ControllerBase {
[HttpGet]
public Student? GetStdInfo(int id) {
if (id == 18) {
return new Student("张三", 20, 18);
} else {
return null;
}
}
}
}

控制器与返回值

控制器可以不继承ControllerBase,不继承的类更方便单元检测,但是会少了很多好用的方法,所以一般建议继承。
action函数支持异步。
可以让action函数返回IActionResult类型,但是不包含类型信息,因而Swagger等无法推断出类型,需要手动通过Ok()或NotFount()等方法转为IActionResult格式,所以更推荐用ActionResult<T>类型做返回值,T为实际返回类型,它支持类型转换(重写了隐式转换运算),从而用起来更简单。
web api中Action方法的返回值如果是普通数据类型,那么返回值就会默认被序列化为Json格式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[HttpGet]
public IActionResult GetStdInfo(int id) {
if (id == 1) {
return Ok(new Student("张三", 20, 1));
} else if (id == 2) {
return Ok(new Student("李四", 21, 2));
} else {
return NotFound("学生不存在");
}
}
[HttpGet]
public ActionResult<Student> GetStudent(int id) {
if (id == 1) {
//可以将任何类型转为ActionResult类型
return new Student("张三", 20, 1);
} else if (id == 2) {
return new Student("李四", 21, 2);
} else {
//非泛型ActionResult可以隐式转换为泛型ActionResult
return NotFound("学生不存在");
}
}

Action方法的参数

1、在[HttpGet]、[HttpPost]等中使用占位符比如{schoolName}捕捉路径中的内容,从而供Action方法的参数使用。
[HttpGet(“/School/{SchoolName}/class/{classNum}”)]
捕捉的值会自动赋值给Action中的同名参数,如果名字不一致可以用[FromRoute(Name=”名字”)]。
2、使用[FromQuery]来获取QueryString中的值,如果名字一致,只要为参数添加[FromQuery]即可;如果名字不一致,则需要[FromQuery(Name=”名字”)],与[FromRoute(Name=”名字”)]使用方法一致,这里不做演示。
3、QueryString和Route可以混用。
注意:一定要设置请求头中的Content-Type为application/json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
[HttpGet]
public UserInfoRequest UserInfo(string Name) {//localhost:7190/Test?Name=张三 从QueryString获取参数
var UserInfo = new UserInfoRequest();
UserInfo.Email = "abc@123.com";
UserInfo.Name = Name;
UserInfo.Password = "password";
return UserInfo;
}
[HttpPost]
public string UserInfoRequery(UserInfoRequest userInfo) {//localhost:/Test/从请求体获取参数
Console.WriteLine(userInfo.Name);
Console.WriteLine(userInfo.Email);
return "ok";
}
[HttpGet("{Value1}/{Value2}")]//localhost:7190/Test/66/99 从URL获取params参数
public string GetValues(int Value1, int Value2) {
return $"Value1:{Value1},Value2:{Value2}";
}
[HttpGet("A/{B}/C/{D}")]
public object GetABCD(int B, [FromRoute(Name ="D")] int Dd) {//localhost:7190/Test/GetABCD/A/66/C/99
return new { B=B , D=Dd };
}
[HttpGet("{id}")]
public object MixTest([FromRoute] int id, string name) {//localhost:7190/Test/MixTest/3?name=张三
return new { id = id, name = name };
}


从Content-Type为multipart/from-data的请求中获取数据的[FromFrom]。
从请求报文头中获取值的[FromHeader]。

处理跨域

CORS原理:在服务器的响应报文头中通过access-control-allow-origin告诉浏览器允许跨域访问的域名。
在Program.cs的 “var app = builder.Build()” 这句之前注册

1
2
3
4
5
6
7
8
9
10
11
string[] urls = new []{"http://localhost:3000"};
builder.Services.AddCors(
options=>{
options.AddDefaultPolicy(
builder=>builder.WithOrigins(urls)
.AllowAnyMethods()
.AllowAnyHeader()
.AllowCredentials();
);
};
);

在Program.cs的 “app.UseHttpsRedirection()”这句代码之前加一句”app.UseCors();”

1
2
app.UseCors();//使用中间件
app.UseHttpsRedirection();