开箱即用~基于.NET Core的统一应用逻辑分层框架设计
目前公司系统多个应用分层结构各不相同,给运维和未来的开发带来了巨大的成本,分层架构看似很简单,但保证整个研发中心都使用统一的分层架构就不容易了。
那么如何保证整个研发中心都使用统一的分层架构,以达到提高编写代码效率、保证工程统一性的目的?
这里给出个人的规划设计,希望对你有所启发。
1.分层目标
- 简单易用:少即是多,哪怕应届生进来也能很快上手
- 结构统一:不管是新系统还是旧系统结构的是一样的。
- 提高效率:提高开发和运维效率,减少维护和学习成本
2.分层架构介绍
先简单介绍当前两种比较流行的分层架构体系:领域分层架构和传统三层架构
2.1领域分层架构
领域架构:包括仓储层、领域层、应用服务层、表现层和基础公共层,如下图所示:
2.2传统三层架构
另一种是相对传统地分为三层:包括数据层、业务逻辑层和表现层,如下图所示:
2.3二者区别?
在早期做三层架构的时候,大都以表来驱动,在做领域架构的时候,大都以业务逻辑来驱动,两者的区别确实比较明显,但到了现在,如果都以业务逻辑为中心,那么两者并没有本质区别。
携程公司采用了第二种分层法,他们希望把分层做得极简,也就是说,哪怕刚毕业进入公司的员工,在分层时基本上也不会乱。
相对于第一种分层法,第二种分层法简单得多。每一个应用的代码量都不应该很大,一旦工程变得过大,就会把它适当拆分,而不是全部放在一单体应用里。
总之,分层越简单,整个软件结构就越清晰,代码就越容易统一。
把工程做得极简,才有利于复制,有利于业务的快速构建,有利于规模化,使系统稳定可靠。
3.统一分层规范
以上两种逻辑分层如何做选型?我们要回到分层的目的上来评估,我们的目标是简单、统一、高效。所以传统的三层架构很好的满足了我们的需求。而领域驱动开发,对DDD有一定的学习成本,同时对旧系统的历史包袱,比如数据库,我们无法做到面向领域编程,我们更多的要面向数据库编程。所以,当前敏捷框架比较适合想从老系统迁移的,但是有数据库历史包袱的团队。如果您的项目中不存在历史包袱,那么可以参考我的另外一篇的设计文章:《开箱即用~基于.NET Core的敏捷开发框架》
3.1减少私人定制:
减少私人通用帮助类CommonLayer的编写,如果每一个应用中有大量相同的帮助类,则在架构层面上是有问题的。线上应用越多,则代码重复越多。比如,每个应用都有分页帮助类、数据库帮助类、缓存帮助类、MQ帮助类、日志帮助类、AOP帮助类等。
每一个应用都是特别的,都需要私人定制极少有通用的代码,如果有,那么应该由框架或组件专门解决。这里框架统一放在Com.Util里。

3.2内聚大于解耦:
内聚是指部门内有共同的目标,然后大家紧密合作。解耦是指部门间各自职责明确,然后减少不必要的连接。一个应用如同一个部门,应该有一个共同的目标和职责,然后大家紧密合作。
换句话说,应用内部应减少不必要的契约接口,减少不必要的依赖注入实现,减少不必要且代价过大的解耦。一切以简单实用为主,应用的价值输出为导向。
总之,无论采取何种分层架构,分层架构最核心的一点就是要保证各层之间职责足够清晰,边界足够明显,让人看到架构图后就能看懂整个架构。
4.分层规范实践
4.0命名规范遵循:
- 简单
- 可读
- 优雅
4.1表现层规范
(1)项目命名规则:
- 如果是API服务,则命名规则为:{公司}.{业务名}.API
比如:Com.Channel.API
- 如果是MVC站点,则命名规则为:{公司}.{业务名}.MVCSite
比如:Com.Channel.MVCSite
4.2逻辑层规范
(1)项目命名规则:{公司}.{业务名}.Business
比如:Com.Channel.Business
(2)类名以Logic结尾
4.3数据层规范
(1)项目命名规则:{公司}.{业务名}.{数据库}DB
比如:Com.Channel.MSSQLDB
(2)约定在应用中使用SQL语句,不使用存储过程。旧的存储过程可以继续使用和修改。
(3)使用数据库的最新特性进行分页
4.4实体层规范
- DTO规范
(1)项目命名规则:{公司}.{业务名}.DTO
比如:Com.Channel.DTO
(2)请求参数DTO实体类放在Request文件夹下,且命名规则为以Request结尾,如下图的 SearchColorRequest.cs
(3)响应DTO实体类放在Response文件夹下,且命名规则为以Response结尾,如下图的 SearchColorResponse.cs
(4)如果请求或响应的DTO实体类的属性中有对象或枚举,那么这些对象所属的类、枚举放在DTO项目的Common文件夹下。
(5)如果请求或响应的DTO实体类有基类要继承,那么约定为基类取名为RequestBase.cs、 ResponseBase.cs,且这些基类直接放在DTO项目的Common文件夹下。
- VO规范
(1)项目命名规则:{公司}.{业务名}.ViewModel
比如:Com.Channel.ViewModel
(2)VO实体类约定用Controller作为文件夹名称
(3)VO实体类名的命名约定:
- 请求VO以Input/Form/Query结尾,如下图的Colorlnput.cs
- 响应VO以Output/List/Result结尾,如下图的ColorOutput.cs
4.5公共层规范
(1)项目命名规则:{公司}.{业务名}.Util
比如:Com.Channel.Utility
4.6测试层规范
(1)项目命名规则:{公司}.{业务名}.UnitTest
比如:Com.Channel.UnitTest
(2)单元测试类格式约定
- 1.一个测试方法只测试一个问题
- 2.使用Moq框架4.11.0
- 3.使用FluentAPI https://fluentassertions.com/
- 最后修改人:张飞洪
- 最后修改时间:2019-6-20
(3)测试方法命名约定
测试方法名分成三段:主题+期望结果+参数
4.6参数校验层规范
我们知道参数校验对整个系统的安全性和性能来说是很重要的一个环节。
- 那么我们的参数校验应该怎么做才能让自己满意呢?
- 也就是说怎样才能让到处都存在的参数校验变得优雅呢?
因为参数校验属于非业务性代码,所以我的想法是使用AOP把他切割出来,不能让校验代码和业务逻辑耦合,而且散落在各处,为此我把校验类独立出来,如下图所示:
在Controller层的做法也很简单,就是绑定一下即可,如下图所示:
5.其他规范
5.1DB配置规范
(1)配置文件分开发环境和生产环境
(2)数据库连接的配置读写分离,链接字符串加密处理
(3)数据库连接配置名的命名规则:{业务}_DB_CONN_读写类型(如上图所示)
5.2配置文件规范
(1)统一使用json文件的配置方式
(2)json文件的读取
- 映射对象
- 统一走AppSetting封装类,通过冒号(:)进行读取
- 数据库做读写分离
5.3静态资源文件规范
(1)公共的静态资源文件(CSS、JS、Image等)放在另外的静态站点中,统一由前端进行开发和维护。一般CSS文件放在css文件夹下,JS文件放在js文件夹下, Image图片文件放在img文件夹下,如下图的左半部分所示。(截图说明,如下图所示:)
(2)静态资源文件必须使用版本号管理,以免更新后由于客户端浏览器缓存而导致站点使用的依然是旧版本的静态资源文件:
<script src="~/js/order.js?v=(Appsetting.StaticFileVersion"></script>
(3)采用前后端完全分离的方式,让Java或NET开发资源撤出表现层,以专注于业务逻辑需求的迭代。
源码下载:
下载
本篇博客经过数日熬夜,反复删减代码,一步步搭建完成后整理的个人心得,分享给大家~~~,所需的源代码,上传在我的腾讯工蜂Git中,打赏博主一杯咖啡钱,然后私密博主~
如果您不想付出,那么请您加入Q群(996767213),并上传您的资源,比如电子书或者其他资料,对群友有帮助的即可。
下载需要简单注册工蜂并把工蜂的用户名给我(如下图所示)
运行
您下载后,所要做的工作就是运行,然后就看到Swagger了(如下图所示)
框架后续
该框架全部利用自己业余时间进行设计和优化,后续会陆续推出其他的系列:
版本系列
- 单体敏捷框架
- AF3(Agile Framework3),基于三层逻辑概念划分;
- AFD(Agile Framework DDD),基于DDD驱动设计原理划分;
- 微服务敏捷框架
- AMFS(Agile Microservice Framework Single Repository),基于单体代码仓库划分;
- AMFM(Agile Microservice Framework Muti-Repository),基于代码多仓库划分;
开箱即用~基于.NET Core的统一应用逻辑分层框架设计的更多相关文章
- 基于AOP的iOS用户操作引导框架设计
背景 有一种现象,App设计者觉得理所当然的操作方式,却常常被用户所忽视,为了防止这种现象发生,就要为App设计一个帮助,一种低成本的方案是将帮助文档写成HTML然后展示给用户,这样的方式常常不能带来 ...
- 【Qt编程】基于Qt的词典开发系列<一>--词典框架设计及成品展示
去年暑假的时候,作为学习Qt的实战,我写了一个名为<我爱查词典>的词典软件.后来由于导师项目及上课等原因,时间不足,所以该软件的部分功能欠缺,性能有待改善.这学期重新拿出来看时,又有很多东 ...
- 基于.NET Core的Hypertext Application Language(HAL)开发库
HAL,全称为Hypertext Application Language,它是一种简单的数据格式,它能以一种简单.统一的形式,在API中引入超链接特性,使得API的可发现性(discoverable ...
- 基于DotNet Core的RPC框架(一) DotBPE.RPC快速开始
0x00 简介 DotBPE.RPC是一款基于dotnet core编写的RPC框架,而它的爸爸DotBPE,目标是实现一个开箱即用的微服务框架,但是它还差点意思,还仅仅在构思和尝试的阶段.但不管怎么 ...
- 基于.NET CORE微服务框架 -谈谈surging API网关
1.前言 对于最近surging更新的API 网关大家也有所关注,也收到了不少反馈提出是否能介绍下Api网关,那么我们将在此篇文章中剥析下surging的Api 网关 开源地址:https://git ...
- 基于.net core 2.0+mysql+AceAdmin搭建一套快速开发框架
前言 .net core已经出来一段时间了,相信大家对.net core的概念已经很清楚了,这里就不再赘述.笔者目前也用.net core做过一些项目,并且将以前framework下的一些经验移植到了 ...
- 基于.NET Core 框架搭建WebApi项目
一 什么是.NET Core? 随着2014年 Xamarin和微软发起.NET基金会,微软在2014年11月份开放.NET框架源代码.在.NET开源基金会的统一规划下诞生了.NET Core .也就 ...
- 基于.net core 微服务的另类实现
基于.net core 的微服务,网上很多介绍都是千篇一律基于类似webapi,通过http请求形式进行访问,但这并不符合大家使用习惯.如何像形如[ GetService<IOrderServi ...
- Core + Vue 后台管理基础框架9——统一日志
1.背景 前阵子有园友留言,提到日志相关的东西,同时,最近圈子里也有提到日志这个东西.一个充分.集中的统一日志平台还是很有必要的,否则系统出问题了只能靠猜或者干瞪眼.何谓充分,日志记录满足最低要求.出 ...
随机推荐
- day1-初识Python之变量
1.python安装与环境配置 1.1.Windows下的python解释器安装 打开官网 https://www.python.org/downloads/windows/ 下载中心 测试安装是否成 ...
- @noi.ac - 508@ 01背包
目录 @description@ @solution@ @accepted code@ @details@ @description@ 有一天你学了一个能解决01背包问题的算法,你决定将这个算法应用到 ...
- 学习layui框架
Layui是一款功能齐全的前端框架,需要引入对应的CSS文件和JS文件,附属官网链接:Layui官网
- Layout布局(补充)
HBoxLayout和VBoxLayout HBoxLayout和VBoxLayout布局都比较简单,也叫箱式布局,它按照先后顺序进行横向布局或垂直布局.另外这两种布局也提供了pack属性支持,设置内 ...
- Laravel获取所有的数据库表及结构
遇到一个需求,需要修改数据库中所有包含email的字段的表,要把里面的长度改为128位.Laravel获取所有的表,然后循环判断表里面有没有email这个字段.代码如下: use Illuminate ...
- nano使用说明
Main nano help text The nano editor is designed to emulate 仿真.模拟 the functionality and ease-of-use o ...
- 2019-1-16-git-subtree-pull-错误-Working-tree-has-modifications
title author date CreateTime categories git subtree pull 错误 Working tree has modifications lindexi 2 ...
- scrapdy部署爬虫项目
原文:https://blog.csdn.net/JLaiRen/article/details/82902321 scrapyd安装 打开命令行工具输入命令:pip install scrapyd ...
- 4-2 setting中一定要将ROBOTSTXT_OBEY = False的注释去掉
# Obey robots.txt rules##默认遵循robots协议的,默认去读取每个网站上的robots协议ROBOTSTXT_OBEY = False
- Python--day37--守护进程和几个常用的方法
1,p.daemon = True #设置子进程为守护进程 #守护进程会随着主进程的代码执行完毕 而结束 #子进程 --> 守护进程 import time from multiprocessi ...