不吹不黑,跨平台框架AspNetCore开发实践杂谈
前言
最近边学边做,初步上手了AspNetCore的开发,对MVC这套熟悉了一下,因为之前没有拿来做过独立项目,都是和别人合作开发,所以前后端分离,我都只做WebApi,而且还是很小的项目(课设级别),生产环境用最多的应该是Python的Django框架,这次我把一个之前做的Django项目用AspNetCore重写一遍,性能提升了不少,C#的性能真不是盖的,AspNetCore这个框架的性能也很不错,榜上有名的(WebApi),虽然MVC排不上名,但是性能依旧甩Django很多,Django每次上线前就做各种性能优化,恐怖,不过性能太好也不行,等会公司觉得工作量不饱和(逃)
ok,既然是杂谈,那也不用把条理梳理得很清楚,我随意列几个方面对比其他框架(Django和Spring之类)聊一聊~
由于我是初学者,对各种概念的理解可能有偏差的地方请各位大佬指正,也欢迎大家一起交流哈哈
对.Net感兴趣的同学可以看看我之前写的C#系列文章,一直在更新,共勉!
依赖注入
对于写习惯Django的我来说,依赖注入以前是很少用到的,刚刚搜了一下,发现Stack Overflow上有一个讨论(Why is IoC / DI not common in Python?)说得不错,给我扫盲了一下,传送门:https://stackoverflow.com/questions/2461702/why-is-ioc-di-not-common-in-python
Python的模块是天生单例模式的,比起Java这种甚至单例模式有多少种实现方式都能进面试题的语言,不知道高到哪里去了,C#好很多,有静态类,不过在开发中还是会以Singleton模式注册到IoC容器中来实现单例~
依赖注入有个很形象的类比,就是把静态语言当成动态脚本语言来用:启动时把一堆东西丢进去IoC容器里,等到要用的时候告诉容器要给你什么,容器就帮你生成,而在容器里面的这堆东西又可以导入别的依赖,这样层层下来相互依赖,如果框架运行过程出问题的话排查起来很痛苦hhh,还要注意避免因为设计问题导致循环依赖等各类问题,所以感觉Django在设计上还是好,生产力是真的高,其他Web框架用得少,除了AspNetCore和Django这些,就用了传统的Spring、Beego和其他小众语言的MVC框架(我甚至用过dart写后台,然并卵),有时间试试新兴的的Vert.x、WebFlux这类,应该会比较好玩~
就这个IoC和DI来说AspNetCore和Spring差不多,功能上差不多,使用方法也差不多,hhh,不过写起来肯定是不如Python畅快的,不过为啥我还要用AspNetCore这种东西呢,因为静态类型语言写起来爽呀,Drf写接口特别快,但是写起来基本靠猜,哈哈哈,感觉这个形容很贴切。最近有个FastApi的看起来不错,据说是100%的类型注解,可以把Python当成静态类型语言来写,但是这种框架太新了,没有经过市场的验证,很难在生产环境用上…
ORM
数据库操作是现在Web框架的核心(误?),我也不知道,反正Web开发基本就是CRUD,整天和数据库打交道是没错的,所以ORM很重要,设计合理好用的ORM可以减少很多工作量,Django为啥受欢迎一大原因就是它的ORM很强大很好用,这应该也是动态语言的优势之一吧。
.NetCore平台上的其他ORM我只用过EF Core和Chloe(官网:https://github.com/shuxinqin/Chloe),这个Chloe也是一个国产ORM,用起来蛮方便的,但是不支持数据库迁移,没办法根据代码生成数据库表,这点还是有点不爽的。EFCore是微软官方的ORM,自然是好用,支持数据库迁移,这个就很方便了,然后其他特点我也总结不出来,因为用得不深,没啥特别的体会。
这次项目我选的ORM是国产的FreeSQL,原因是偶然间在博客园看到作者王婆卖瓜的文章,觉得还不错,然后就拿来用一用,确实挺好用的,可以很轻量一句话完成数据库连接建立,也可以像EFCore那样有各种丰富的功能,而且也支持DB First,这个就很舒服了,这次因为是把Django项目迁移到AspNetCore,所以我打算先用原来的数据库试试看,然后FreeSQL一通DB First之后居然美滋滋的可以用,就更坚定了要继续用下去的信心,哈哈(虽然后面遇到了很多坑,大多是关于多对多关系的,被DjangoORM惯坏了)
FreeSQL官网文档:https://github.com/dotnetcore/FreeSql/wiki
体验下来,FreeSQL对外键(一对多、多对一)、多对多、一对一关系的处理方式还是可以的,通过「导航属性」,跟EFCore应该差不多,但是定义Model的时候如果有外键,还有多定义一个字段存Id,这点感觉有点反人类了,EFCore不用,直接引用对象即可,迁移之后反映到表里就是一个外键Id,不过这个FreeSQL是软外键,引用归引用,关系全都在代码里面处理,不在数据库里面生成外键,这个也有它的好处,甚至可以说是一个优势了,有时候维护表的完整性约束有点麻烦hhh
参考文章:.NET ORM 导航属性到底可以解决什么问题?https://www.cnblogs.com/kellynic/p/13575053.html
然后再小小对比了一下Kotlin的Ktorm,这也是一个优秀的ORM,上次我也小小的试用了一下,挺不错的,除了没有迁移功能没法自动建表,这个Ktorm用起来类似EFCore的体验,同样是外键直接引用就行,不用像FreeSQL那样留一个Id字段来保存,各有利弊吧…不展开了
PS:之前的文章里吐槽了Ktorm之后被作者大佬看到找上来手把手指导我写代码了(逃),有些坑真不是框架的问题,还是自己太菜了啊…
数据库
数据库我用SQLite,反正小项目我全都用这个,性能好,部署方便,虽然有写入锁,但就几个人在用的系统,要啥自行车?
- 记一次 SQLite 性能优化 https://www.isaced.com/post-272.html
- 每天4亿行SQLite订单大数据测试 https://cloud.tencent.com/developer/article/1016993
ViewModel
ViewModel在分层架构中很重要,其实除了ViewModel还有一个叫DTO(Data Transfer Object)的概念,ViewModel和DTO在MVC架构中同属于Model层,DTO也可以叫做Input Model,因为一般作为外部传入数据的对象(顾名思义嘛),然后通常总是在说的Model,其实也可以叫Entity,这些对象是直接对应到数据库中的表,一般在View或者Api中不直接呈现Model,而是呈现ViewModel,因为可能我们会对要输出的数据做一些处理啦,比如增加字段删除字段这些,用Model肯定不行,数据表都是固定的。
同理,在传入数据的时候,和数据表也不一定重合的,所以需要借助DTO,其实和ViewModel没什么严格的界限,你要拿DTO去呈现也行,只是我觉得ViewModel看名字就是拿来呈现的,习惯哈哈。
其实传统的MVC、MVVM模式都已经有点跟不上时代了,我觉得现在的Web应用就得按照DDD(Domain-Driven Design)模式来设计,不过DDD初学有点复杂,概念很多,我也不好乱解释,引用一下知乎的一段回答:
DDD简单说是: 一个项目里面有多个Bounded Context, 譬如说一个是前台面向用户的,一个是后台面向公司内部人员的。每个Bounded Context里面会分为多个aggregate。每个aggregate里面包含了一堆需要保证事务性一致的物体,也就是说从全局来说,每个aggregate都是当作一个整体。常见的例子就是Order(订单)和OrderLine(订单里面的商品)。Entity包括Aggregate root都有唯一标识。两者的区别是aggregate root全局里面有唯一标识,而aggregate 内部其他entity只是在aggregate内部有唯一标识(也许你数据库里面有主键,但是这边是指概念上来说这个唯一标识对全局来说意义不大,只有在aggregate内部意义才大)。另外的value object就是没有标识的物体,他们的意义就在于它的值,你可以想象成比较两个entity是不是同一个只需要判断ID是否相等,而判断value objects需要看里面的每个属性是否一样。
作者:鲍牙叔
链接:https://www.zhihu.com/question/25256772/answer/77940547
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
然后,这么多对象在转来转去,又有很多字段是差不多的,一个个重新赋值显得很傻也根本没必要,这个时候AutoMapper就要用起来了,具体用法不是本文的讨论范围(参考下方列出的官方文档),不过提一点,AutoMapper是可以配置的,有哪些字段不要的可以排除,我在Profile中是这么写的:
public class VideoProfile : Profile {
private readonly List<string> _unmapped = new List<string> {
"HostEnvironment", "Previews", "OverallRating"
};
public VideoProfile() {
CreateMap<Video, VideoViewModel>();
ShouldMapProperty = (property) => !_unmapped.Contains(property.Name);
}
}
把不要的字段放在一个List里面,然后用lambda配置 ShouldMapProperty 就好啦。
参考
- AutoMapper https://docs.automapper.org/en/latest/Getting-started.html
- RESTful+FreeSql+AutoMapper https://luoyunchong.github.io/vovo-docs/dotnetcore/examples/freesql-sample-blog-restful-use-automapper.html#adding-profiles
- FreeSql、AutoMapper处理多对多查询映射 https://blog.csdn.net/XinShun/article/details/104755959
一些关于C#语言的
C#语言我用很久了,但是却几乎没有专门去学习过语法,这门语言,emmm,下限低,上限很高,上手很简单,但复杂度比Java高很多,语法糖很多,所以圈子里的人很多有种高人一等的优越感哈哈,但其实国内的生态是比较差啦,有就是一些培训班啥的在吹,不过国外可以感觉到是比较热门的一个技术,平时遇到啥问题,可能用中文关键词搜不到,但是换成英文可以轻松搜索到很多高质量的答案,只能说国内的技术环境被阿里之类的大厂带偏了,大家都去搞Java了,很多其他好技术和好的语言无人问津,可惜啊……
这次项目也没用到啥高大上的东西,就是泛型、扩展方法、高阶函数这类,用得飞起,贴一小段代码来看看哈哈~
public static IList<TViewModel> ToViewModels<TModel, TViewModel>(
this ISelect<TModel> data,
IService<TModel, TViewModel> service,
int limit = 0
) where TModel : class
where TViewModel : class {
var limitData = limit == 0 ? data : data.Limit(limit);
return limitData
.ToList()
.Select(service.Get)
.ToList();
}
public static IEnumerable<TViewModel> ToSampleViewModels<TModel, TViewModel>(
this ISelect<TModel> data,
IService<TModel, TViewModel> service,
int limit = 0
) where TModel : class
where TViewModel : class {
return data.ToViewModels(service)
.Shuffle()
.Take(limit);
}
这个代码就是把FreeSQL查询数据库的结果一键转换为ViewModel,转换过程是通过Service,功能很简单,但是做成扩展方法然后调用真的不要太爽,减少了n多代码重复,很舒服~
然后C#的高阶函数一开始我有点不习惯,因为之前写习惯python、dart和js,都是map、reduce、filter这些,但是C#的LINQ中却换了个名字,map对应select、filter对应where,这就很像SQL的风格了,我一开始都找不到……
总之C#语言值得好好学一学,对提高工作效率和编程思维是有帮助的!多看书就完事了!
参考资料
几个库
另外还有看到好像蛮不错的几个库,我还没用,目前已经把AspNetCore应用到工作中了,以后应该有机会把这些库用上hhh
- Util应用框架:https://github.com/dotnetcore/Util/blob/master/readme.md
- Masuit.Tools:https://github.com/ldqk/Masuit.Tools
欢迎交流
我整理了一系列的技术文章和资料,在公众号「程序设计实验室」后台回复 linux、flutter、c#、netcore、android、kotlin、java、python 等可获取相关技术文章和资料,同时有任何问题都可以在公众号后台留言~