在 14,15 年间带领几个不同的团队, 交付了几个项目, 在这个过程中, 虽然几个项目的业务不一样, 但是很多应用程序架构基础性的功能却是大同小异, 例如认证授权请求验证异常处理 DTO 日志审计定时任务调度多语言应用配置管理等等这些功能但是由于项目受限于进度资源团队成员的背景, 在当时却难于做到各个项目的统一, 只能用拷贝的方式, 然后在不通的项目中各自再根据各自的需求去做改进这促使我下定决心去整理实现一个通用的应用程序级别的框架, 来提升项目交付的效率和质量
在整理这个框架的过程中, 参考了一些开源框架的设计和实现, 无意中发现了 ABP(ASP.NET Boilerplate)已经实现的正是我想要的, 本着不重复造轮子的原则, 在对 ABP 做了 POC 和评估后, 在向整个评审小组展示时, 尽管有诸多细节大家意见不尽相同, 但对于整体框架却是少有的一致好评, 在后来的项目交付中使用 ABP 也就是顺利成章的事了当时 ABP 的版本还是 0.5(现在的最新版本是 3.5), 尽管也踩了一些坑, 但是总的来说还是大幅的提高了项目交付效率
好了, 废话不多说, 我们进入正题
什么是 ABP
ABP(ASP.NET Boilerplate)是一个开源的应用程序框架, 以帮助开发人员快速开发但它又不仅仅是一个框架, 更提供了一套基于 DDD 的架构模型和最佳实践
快速示例
下面我们来研究一个最简单的示例来看看使用 ABP 好哪些好处
- public class TaskAppService : ApplicationService, ITaskAppService
- {
- private readonly IRepository<Task> _taskRepository;
- public TaskAppService(IRepository<Task> taskRepository)
- {
- _taskRepository = taskRepository;
- }
- [AbpAuthorize(MyPermissions.UpdateTasks)]
- public async Task UpdateTask(UpdateTaskInput input)
- {
- Logger.Info("Updating a task for input:" + input);
- var task = await _taskRepository.FirstOrDefaultAsync(input.TaskId);
- if (task == null)
- {
- throw new UserFriendlyException(L("CouldNotFindTheTaskMessage"));
- }
- input.MapTo(task);
- }
- }
这里我们看到的是一个 Application Service 类, TaskAppService, 里面定义了一个方法 UpdateTask. Application Service 在 DDD 的设计中是直接被展示层所调用的, 简单来说, 一个前端页面可以直接调用 TaskAppService.UpdateTask.
就这个简单的示例, 我们一起来看看使用 ABP 有哪些好处
依赖注入 - ABP 提供了一个惯用的 DI 基础框架, 所谓惯用, 就是大家平常使用的 DI 方式一致, 保持大家的使用习惯因为这个示例是在应用服务层, 所以注入容器中的实例生命周期都是短时的(每个请求创建一次, 生命周期与请求相同) 它可以简单方便的注入任何依赖, 比如在本示例中的 IRepository
仓储 - ABP 可以为每一个实体都创建一个默认仓储, 在示例中是 IRepository
授权 - ABP 可以使用声明式的方式来检查权限在示例中, 如果一个用户没有登录, 或者没有 UpdateTasks 的权限, 那么他将不能访问 UpdateTask 方法 ABP 不单单使用声明式的特性来检查权限, 它还提供了其他的授权方式
请求验证 - ABP 自动的检查请求输入 (input) 是否为 null, 并且可以基于标准的数据注解和自定义验证规则来检查输入中的属性是否合法如果请求不合法, 它将会抛出一个验证异常
审计日志 - ABP 会基于惯例和配置, 自动为每一个请求记录访问的用户浏览器 IP 地址调用的服务方法参数调用时间耗时和其它一些信息
工作单元 - 在 ABP 中, 每个应用服务方法, 都被默认视为一个工作单元. 在进入方法时, ABP 会自动的打开连接并开启事务, 如果方法在执行过程没有任何异常, 并且成功完成, 那么在退出方法时, ABP 会自动提交事务并释放连接不管方法中使用了一个还是多个仓储, 他们都是原子的, 在一个事务中, 所有的实体改变都会在事务提交时自动保存正如示例中所示, 我们甚至都不用调用显示的 '_repository.Update(task)'方法来保存数据更新 不过我个人建议尽管可以不显示调用更新, 但是从代码的可读性和可维护性还是显示的调用'_repository.Update(task)'方法
异常处理 - 在 ABP 我们几乎不用手动的来处理异常, ABP 会默认自动处理所有异常如果有异常发生, ABP 会自动的记录它, 并返回合适的结果给客户端例如, 如果这是一个 AJAX 请求, 它会返回一个 JSON 对象给客户端, 并指明有一个错误发生它会向客户端隐藏真实的异常, 除非我们使用 UserFriendlyException.
日志 - 我们可以使用基类中定义的 Logger 对象来写日志 ABP 默认使用 Log4Net 来写日志, 当然我们也可以通过修改配置来使用其他的日志框架
本地化(多语言)- 在示例中, 当抛出异常时, 使用了 "L" 方法, 它会根据用户文化配置自动进行本地化处理
自动映射 - 在示例的最后一行, 我们使用了 ABP 的 MapTo 扩展方法来讲输入对象的属性映射到实体对象的属性它使用了 AutoMapper 库来执行映射, 我们可以很容易的基于命名约定 (简单来讲就是属性名相同, 当然也可以指定) 来将一个对象的属性来映射到另一个对象的属性通常不同层都会定义自己的数据对象模型, 而在层与层之间进行数据交换时, 就设计到不同数据对象的转换, 这个时候就是 AutoMapper 大显身手的好时机
动态 API 层 - TaskAppService 只是一个一般的类, 通常我们需要写一个 web API Controller 包装器来将 TaskAppService 的方法以 API 的形式暴露给客户端调用, 但是 ABP 在运行时已经自动为 AppService 的方法生成了 API 接口, 所以这样看起来, 就像是客户端直接调用了 AppService 的方法(但实际不是)
动态 Javascript AJAX 代理 - ABP 在前端为应用服务的调用创建了代理方法, 这样就可以在前端像调用 Javascript 方法一样调用应用服务
在示例中, 我们可以看到使用 ABP 的优势, 通常如果我们来做这些事情, 会花费大量的时间, 但是 ABP 框架都自动的为我们处理了这里必须点个赞了
此外, 除了这个示例中展示的 ABP 的优势以外, ABP 还提高了一个健壮的基础架构和应用模型包括模块化多租户缓存配置管理调度和后台任务数据过滤领域时间单元测试和集成测试等等它让我们可以集中关注在业务实现上, 而不用重复的去造轮子
来源: https://www.cnblogs.com/lcyhjx/p/8688880.html