6.3 ASP.NET Core Web API技术选择
控制器父类
Controller
继承自ControllerBase
,只不过增加了视图相关的方法,一般mvc项目选用Controller
而Web API项目选择ControllerBase
即可。
操作方法的返回值和状态码
ASP.NET Core Web API中的操作方法返回值如果是普通数据类型,则返回值默认被序列化为JSON格式的响应报文体返回。
ASP.NET Core Web API也支持IActionResult<T>
类型
[Route("api/[controller]/[action]")]
[ApiController]
public class TestController : ControllerBase
{
[HttpGet("{id}")]
public ActionResult<Person> GetPerson(int id)
{
if (id <= 0)
{
return BadRequest("id必须是正数");//继承自ACtionResult
}
else if (id == 1)
{
return new Person(1, "tom", 18);
}
else if (id == 2)
{
return new Person(2, "Zack", 8);
}
else
{
return NotFound("人员不存在");//继承自ACtionResult
}
}
}
对于失败的请求,一般要统一响应报文体的格式以便在客户端进行处理。
public record ErrorInfo(int Code, string? Message);
声明一个表示错误的详细信息类
其中code参数表示错误的自定义业务代码
//使用ErrorInfo改造GetPerson方法
[HttpGet("{id}")]
public ActionResult<Person> GetPerson(int id)
{
if (id <= 0)
{
return BadRequest(new ErrorInfo(1,"id必须是正数"));
}
else if (id == 1)
{
return new Person(1, "tom", 18);
}
else if (id == 2)
{
return new Person(2, "Zack", 8);
}
else
{
return NotFound(new ErrorInfo(2,"人员不存在"));
}
}
//使用BadRequest或者NotFound等可以使得错误码不一致,供开发人员调试
操作方法的参数
给服务器传递参数的时候,有URL、QueryString、请求报文体3种方式
- 访问路径中的值
可以在[HttpGet]、[HttpPost]等中使用占位符{}
来捕捉路径中的内容。案例:
请求路径/Student/GetAll/school/MIT/class/A001
GetAll方法添加了[HttpGet("schllo/{schoolName}/class/{classNo}")]
**结果:**schoolName=MIT和classNo=A001。如果GetAll方法的参数中有和占位符名字同名的参数,那么这个参数就会被自动赋值。如果占位符名字与参数名称不一致,则使用[FromRoute]的Name属性来设置匹配的占位符的名字,例如:
[HttpGet("schllo/{schoolName}/class/{classNo}")]
public ActionResult<Student[]> GetAll(string schoolName,[FromRoute(Name="classNo")]string calssNum) //classNum的参数想获得占位符{classNo}的值
使用[FromQuery]
来获取,如果操作方法的参数名字和QueryString的名字一致,只需要为参数添加[FromQuery],否则,就要设定[FromQuery]的name属性指定名字
//URL的QueryString为pageNum=8&pSize=10
public ActionResult<Student[]> GetAll([FromQuery]string pageNum,[FromQuery)(Name="psize")]int pageSize)
//可以处理/Student/GetAll/school/MIT/class/A001?pageNum=8&pSize=10
[HttpGet("schllo/{schoolName}/class/{classNo}")]
public ActionResult<Student[]> GetAll(string schoolName,[FromRoute(Name="classNo")]string calssNum,[FromQuery]string pageNum,[FromQuery)(Name="psize")]int pageSize)
目前JSON是主流的请求报文体格式,本文讲JSON报文体
案例:
需求:前端浏览器向服务器发送的报文体:{“name”:“qs”,“age”:“18”}
直接声明一个Person类定义Name和age两个属性
[HttpPost]
public ActionResult AddNew(Person p)
客户端只要向/Person/AddNew提交Post提交即可
也可以从URL中获取参数、从请求报文体获取数据混合使用
[HttpPost("classId/{classId}")]
public ActionResult<long> AddNew(long classId,Person s)
//客户端只要向/Students/AddNew/classId/8,伴随报文体{“name”:"yzk","age":"18"}
//通过classId获取8,s参数则是报文体
**注意:**一定设置请求报文头中Content-Type为application/JSON
案例
public record ProcessInfo(int Id,string ProcessName,long WorkingSet64);
public record LoginResult(bool isok, ProcessInfo[]? Process);
public record LoginRequeset(string username,string password);
//Login方法用来判断请求的用户名、密码是否正确,如果正确的话服务器会返回当前计算机的所有进程信息
[Route("api/[controller]/[action]")]
[ApiController]
public class LoginController : ControllerBase
{
[HttpPost]
public ActionResult<LoginResult> Login(LoginRequeset loginreq)
{
if (loginreq.username =="admin" && loginreq.password =="123456")
{
var process = Process.GetProcesses().Select(p => new ProcessInfo(p.Id, p.ProcessName, p.WorkingSet64)).ToArray();
return new LoginResult(true, process);
}
else
{
return new LoginResult(false, null);
}
}
}
前端页面
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>dddd</title>
</head>
<body>
<div id="app">
<div>
<label>账户:</label>
<input type="text" placeholder="账户" v-model="acount" />
<label>账户:</label>
<input type="password" placeholder="密码" v-model="password" />
<button @click="queryprocess">
搜 索
</button>
</div>
<div>
<ul>
<li v-for="(process,index) in processarr">
id: {{process.id}} == processName: {{process.processName}} == workingSet64: {{process.workingSet64}}
</li>
</ul>
</div>
</div>
<script src="./vue.js"></script>
<script src="./axios.min.js"></script>
<script>
var app = new Vue({
el: "#app",
data: {
processarr: [],
acount: "",
password: ""
},
methods: {
queryprocess() {
var that = this;
axios.post("http://localhost:7285/api/Login/Login", {
username: this.acount,
password: this.password
}).then(res => {
if(!res.data.isok)
{
alert("账户密码错误!");
return;
}
that.processarr = res.data.process;
console.log(res);
}, err => { alert("访问出错");});
},
}
});
</script>
</body>
</html>
启动服务后,发现浏览器没有反应,这是因为前端和后端不在同一个域名下(不同的端口也认为是不同的域名),浏览器默认是禁止AJAX跨域。我们可以采用CORS方式,CORS是浏览器中标准的跨域通信方式。CORS的原理是在服务器的响应报文头文件中通过access-control-allow-origin
告诉浏览器允许跨域访问的域名。
我们需要在后端项目中启用CORS,并且设定前端项目的域名。
//在项目Program.cs中的var app = builder.Build();前面加上
string[] urls = new[] { "http://127.0.0.1:5500" };//允许跨域访问的域名
builder.Services.AddCors(options =>
options.AddDefaultPolicy(builder => builder.WithOrigins(urls)
.AllowAnyMethod().AllowAnyHeader().AllowCredentials()));
//最后在app.UseHttpsRedirection();前面加上app.UseCors();