第五章 .net core该怎么玩
项目目标部署环境:CentOS 7+
项目技术点:.netcore2.0 + Autofac +webAPI + NHibernate5.1 + mysql5.6 + nginx
开源地址:https://github.com/wmowm/nh.core
很多小伙伴,初识.net core都不知道如何下手,从哪里开始学习,这让我想起群里经常有小伙伴问,mvc怎么学习?
我觉得,第一步应该找到一个切入点,这里先说mvc,我们分三种情况来分析
1.萌新
我个人觉得,xxx从入门到精通,是不适合去学习的,特别是萌新,这样走马观花的看一遍,根本就起不到任何作用
最好的方法就是用mvc做一些简单的demo,登录,注册,crud.... 这就是切入点
2.从webform转入mvc
直接看mvc的路由,分部页,借助网上的一些资料即可,边做边查,mvc就非常简单了
3.从别的语言转入asp.net
熟悉asp.net的一些特性即可,mvc的设计模式是共通的
回归正题那.net core怎么玩?
还是找切入点,这里我就拿2年asp.net开发经验为原型
切入点就是造轮子,先找我们最熟悉的地方,一步步开始搭建.net core项目
我们这次的轮子是通过web api 实现CRUD,这里我的IDE是vs2017,SDK是.net core 21.4, let's go~~~
第一步,创建一个web api,这里贴出我在使用中遇到的坑
1.RestFul Action共存
在get情况下,相同路由的Action无法共存,运行报错会匹配到多个Action
在post情况下,相同路由的Action可以共存,会存在优先级,但是只会执行一个正则匹配到的Action
2.RestFul 相同路由的Action如何并存,并访问指定的Action
[Route("list"),HttpPost]
路由如下 api/{controller}/list
3.RestFul 如何设置多参数,
[Route("list"),HttpPost("{a}/{b}/{c}")]
路由如下 api/{controller}/list/1/2/3
4.Post提交多参数,[FromBody] 跨域问题
去注册中间件,让webapi支持跨域
5.Post提交多参数,[FromBody] ajax提交类型错误
必须设置:contentType: 'application/json; charset=urf-8'
参数必须格式化成json字符串: data: JSON.stringify(data)
6.关于[FromBody]标识的参数不能设置基础类型,如string...
错误说法,可以设置成string类型
7.为什么Post提交参数必须要标识[FromBody]
[FromBody]表示该参数值应该从请求的Body中获取,而不是从URL中获取,URL有长度限制
在不超过长度限制的情况下,可以随意
第二步,实现web api CRUD
[HttpGet] public async Task<JsonResult> Get(int id) { return await Task.Run<JsonResult>(() => { Common.Json json = new Common.Json(); var model = _UsersService.Get(id); json.data = model; return Json(json); }); }
通过id获取实体对象,这里非常好理解,我们直接去看这个返回的json对象
/// <summary> /// 返回的Json模型 /// </summary> public class Json { private int _status = 0; /// <summary> /// 状态 -1失败,0成功 /// </summary> public int status { get { return _status; } set { _status = value; } } public string pitchId { get; set; }//要定位的页面元素id public string msg { get; set; }//消息 public string returnUrl { get; set; }//跳转的页面 public object data { get; set; }//数据 public int total { get; set; }//总条数 }
这里还加一个属性,显示响应状态,例如token验证不通过,服务端错误500,资源未找到404.....
[Route("getlist"),HttpPost] public async Task<JsonResult> GetList([FromBody]Dictionary<string, dynamic> dic) { return await Task.Run<JsonResult>(() => { Json json = new Common.Json(); //自定义参数模板 List<SearchTemplate> st = new List<SearchTemplate>(); //自定义排序模板 List<SortOrder> order = new List<SortOrder>(); //对参数的操作 foreach (var item in dic.Keys) { //根据用户名模糊查询 if (item == "user_name") { st.Add(new SearchTemplate() { key = "user_name", value = dic[item], searchType = EnumBase.SearchType.Like }); } //根据用户名模糊查询 if (item == "mobile") { st.Add(new SearchTemplate() { key = "mobile", value = dic[item], searchType = EnumBase.SearchType.Like }); } //排序 if (item == "order") { var str = JsonConvert.SerializeObject(dic[item]); order = JsonConvert.DeserializeObject<List<SortOrder>>(str); } //分页 if (item == "paging") { var str = JsonConvert.SerializeObject(dic[item]); int [] paging = JsonConvert.DeserializeObject<int[]>(str); st.Add(new SearchTemplate() { key = "", value = paging, searchType = Common.EnumBase.SearchType.Paging }); } //后面可以根据业务拓展查询条件 } var list = _UsersService.GetList(st, order); var list_count = _UsersService.GetCount(st); json.data = list; json.total = list_count; return Json(json); }); }
前端提交方法
function getlist() { var param = { //"user_name": "admin", "order": [{ "searchType": 1, "value": "id" }], "paging": [1, 10] }; $.ajax({ type: "post", url: path + "/api/user/getlist", data: JSON.stringify(param), async: false, contentType: 'application/json; charset=urf-8', beforeSend: function (xhr) { xhr.setRequestHeader("token", $("#token").html()); }, success: function (data, status) { if (data.status != 0) { alert(data.msg); } else { vm.list = data.data; } } }); }
param 是一个json对象,它由三个部分组成 查询参数:key/value ,排序数组 ,分页数组
后台解析这些参数,我这里用的是动态解析,这样就不用每个model创建一个dto,在NHibernate里我使用的是查询器模式,我只需要把解析的参数填充到查询器即可
这里我自定义了两个模板一个用来传参分页,一个用来排序
[Serializable] public class SearchTemplate { /// <summary> /// 要查询的属性(对应Model里的属性) /// </summary> public string key { get; set; } /// <summary> /// 要查询的属性的值(对应Model里的属性得值) /// </summary> public object value { get; set; } /// <summary> /// 查询类型(>,=,In.....) /// </summary> public Common.EnumBase.SearchType searchType { get; set; } } [Serializable] public class SortOrder { /// <summary> /// 排序方式(Asc,Desc) /// </summary> public Common.EnumBase.OrderType searchType { get; set; } /// <summary> /// 要排序的属性(对应Model里的属性) /// </summary> public string value { get; set; }
查询条件是最容易变更的地方,要考虑到后期拓展,用这种方式是非常好的解决方案,这也体现了NHibernate的强大,除了查询器模式,还是有HQL,Linq,Lamdba....
后面是添加,修改,删除,都非常的简单
[HttpPost] public async Task<JsonResult> Add(Users user) { return await Task.Run<JsonResult>(() => { Json json = new Common.Json(); if (string.IsNullOrEmpty(user.user_name)) { json.msg = "用户名不能为空!"; json.status = -1; return Json(json); } var id = _UsersService.Save(user); json.data = id; json.msg = "添加成功!"; return Json(json); }); }
[HttpPut] public async Task<JsonResult> Edit(Users user) { return await Task.Run<JsonResult>(() => { Json json = new Common.Json(); _UsersService.Update(user); json.msg = "修改成功!"; return Json(json); }); }
[HttpDelete] public async Task<JsonResult> Delete(string ids) { return await Task.Run<JsonResult>(() => { //自定义返回json对象 Json json = new Json(); foreach (var id in ids.Split(new char[] { ',' })) { var m_nt = _UsersService.Get(Convert.ToInt32(id)); m_nt.is_del = 1; _UsersService.Update(m_nt); } json.msg = "成功删除" + ids.Split(new char[] { ',' }).Length + "条记录!"; return Json(json); }); }
这样我们就实现了简单的CRUD,这里存在两个问题
1.json里的时间格式
2.跨域
下章我们将讲解.net core里无处不在的依赖注入