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]
publicclassTestController : ControllerBase
{
[HttpGet("{id}")]
publicActionResult<Person>GetPerson(intid)
{
if (id<=0)
{
returnBadRequest("id必须是正数");//继承自ACtionResult
}
elseif (id==1)
{
returnnewPerson(1, "tom", 18);
}
elseif (id==2)
{
returnnewPerson(2, "Zack", 8);
}
else
{
returnNotFound("人员不存在");//继承自ACtionResult
}
}
}
对于失败的请求,一般要统一响应报文体的格式以便在客户端进行处理。
public record ErrorInfo(int Code, string? Message);
声明一个表示错误的详细信息类
其中code参数表示错误的自定义业务代码
//使用ErrorInfo改造GetPerson方法
[HttpGet("{id}")]
publicActionResult<Person>GetPerson(intid)
{
if (id<=0)
{
returnBadRequest(newErrorInfo(1,"id必须是正数"));
}
elseif (id==1)
{
returnnewPerson(1, "tom", 18);
}
elseif (id==2)
{
returnnewPerson(2, "Zack", 8);
}
else
{
returnNotFound(newErrorInfo(2,"人员不存在"));
}
}
//使用BadRequest或者NotFound等可以使得错误码不一致,供开发人员调试
id | 返回结果 |
-1 |
|| 2 | || 9 | |
操作方法的参数
给服务器传递参数的时候,有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}")]
publicActionResult<Student[]>GetAll(stringschoolName,[FromRoute(Name="classNo")]stringcalssNum) //classNum的参数想获得占位符{classNo}的值
- QueryString中的值
使用[FromQuery]
来获取,如果操作方法的参数名字和QueryString的名字一致,只需要为参数添加[FromQuery],否则,就要设定[FromQuery]的name属性指定名字
//URL的QueryString为pageNum=8&pSize=10
publicActionResult<Student[]>GetAll([FromQuery]stringpageNum,[FromQuery)(Name="psize")]intpageSize)
- 混合使用
//可以处理/Student/GetAll/school/MIT/class/A001?pageNum=8&pSize=10
[HttpGet("schllo/{schoolName}/class/{classNo}")]
publicActionResult<Student[]>GetAll(stringschoolName,[FromRoute(Name="classNo")]stringcalssNum,[FromQuery]stringpageNum,[FromQuery)(Name="psize")]intpageSize)
- 请求报文体
目前JSON是主流的请求报文体格式,本文讲JSON报文体
案例:
需求:前端浏览器向服务器发送的报文体:{"name":"qs","age":"18"}
直接声明一个Person类定义Name和age两个属性
[HttpPost]
publicActionResultAddNew(Personp)
客户端只要向/Person/AddNew提交Post提交即可
也可以从URL中获取参数、从请求报文体获取数据混合使用
[HttpPost("classId/{classId}")]
publicActionResult<long>AddNew(longclassId,Persons)
//客户端只要向/Students/AddNew/classId/8,伴随报文体{“name”:"yzk","age":"18"}
//通过classId获取8,s参数则是报文体
注意:一定设置请求报文头中Content-Type为application/JSON
案例
publicrecordProcessInfo(intId,stringProcessName,longWorkingSet64);
publicrecordLoginResult(boolisok, ProcessInfo[]?Process);
publicrecordLoginRequeset(stringusername,stringpassword);
//Login方法用来判断请求的用户名、密码是否正确,如果正确的话服务器会返回当前计算机的所有进程信息
[Route("api/[controller]/[action]")]
[ApiController]
publicclassLoginController : ControllerBase
{
[HttpPost]
publicActionResult<LoginResult>Login(LoginRequesetloginreq)
{
if (loginreq.username=="admin"&&loginreq.password=="123456")
{
varprocess=Process.GetProcesses().Select(p=>newProcessInfo(p.Id, p.ProcessName, p.WorkingSet64)).ToArray();
returnnewLoginResult(true, process);
}
else
{
returnnewLoginResult(false, null);
}
}
}
前端页面
<!DOCTYPE html>
<html>
<head>
<metacharset="utf-8"/>
<title>dddd</title>
</head>
<body>
<divid="app">
<div>
<label>账户:</label>
<inputtype="text"placeholder="账户"v-model="acount"/>
<label>账户:</label>
<inputtype="password"placeholder="密码"v-model="password"/>
<button@click="queryprocess">
搜 索
</button>
</div>
<div>
<ul>
<liv-for="(process,index) in processarr">
id: {{process.id}} == processName: {{process.processName}} == workingSet64: {{process.workingSet64}}
</li>
</ul>
</div>
</div>
<scriptsrc="./vue.js"></script>
<scriptsrc="./axios.min.js"></script>
<script>
varapp=newVue({
el: "#app",
data: {
processarr: [],
acount: "",
password: ""
},
methods: {
queryprocess() {
varthat=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();