本节内容:
我们总是对不同的需求开发不同的应用。但至少在某些层面上,一次又一次地重复实现通用的和类似的功能。如:授权,验证,异常处理,日志,本地化,数据库连接管理,设置管理,审核日志等功能。所以我们创建架构和最佳实践,如分层和模块架构,DDD,依赖注入等,并尝试开发应用时基于一些约定。
由于所有这些是非常耗时而且很难单独创建并可适用于每个项目,许多公司创建自己的框架,他们用自己的框架能快速开发新应用而且不出错。但不是所有的公司都是幸运的,大部分公司没有时间,预算和团队来开发好的框架。他们甚至都没有可能创建一个框架,因为编写文档,培训开发人员和维护框架都是非常困难的。
ASP.NET Boilerplate (ABP) 是一个开源并且有丰富文档的应用框架,开发宗旨是:“为所有公司,所有开发人员,开发出一个通用框架!”,而且不只是一个框架,同时提供一个强大的基于DDD的构架模型和最佳实践。
让我们从一个简单的类来体会一下ABP带来的便利:
public class TaskAppService:ApplicationService,ITaskAppService { private readonly IRepository<Task> _taskRepository; public TaskAppService(IRepository<Task> taskRepository) { _taskRepository = taskRepository; } [AbpAuthorize(MyPermissions.UpdatingTasks)] 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("CouldNotFoundTheTaskMessage")); } Input.MapTo(task); } }
示例里我们看到一个应用服务方法,在DDD中,应用服务方法是在表示层执行应用的用户用例的。我们可以想成UpdateTask方法是被Ajax调用。让我们看看ABP带来的便利:
- 依赖注入:ABP使用并提供一个强大而且符合约定的DI框架。上述的应用服务,按照约定临时的(每个请求Request创建一个)注册到DI容器,它能简单地注入所有依赖项(如示例中的Irepository<Task>)。
- 仓储:ABP能为每个实体创建一个默认的仓储(如示例中的Irepository<Task>)。默认仓储包含许多有用的方法,如示例中的FirstOrDefault方法。我们可以根据需要,很容易地扩展默认仓储。仓储抽象了DBMS和ORM以及简化了数据访问逻辑。
- 授权:ABP可以检查许可。如果当前用户没有“updating task”权限或是未登录,ABP就会阻止他们访问UpdateTask方法。用陈述性的特性来简化授权,当然还有另外的授权方式。
- 验证:ABP自动检查input是否为null。根据标准的数据注释特性和自定义验证规则,检查一个input的所有属性。如果请求没有通过验证,会抛出一个对应的验证异常。
- 审计日志:根据约定和配置,每个请求的用户、浏览器、Ip地址、调用服务、方法、参数、调用时间、执行耗时和其它的一些信息会被自动地保存下来。
- 工作单元:在ABP里,每个应用服务方法都默认地被认定为一个工作单元。在方法开始前,它自动创建一个连接并开启一个事务。如果方法成功完成,接着事务会被提交并释放连接。即使是使用不同的仓储或是方法,它们都可以是原子性(事务性)的,并且当事务提交时实体中所有的修改都自动地被保存。因此,如同示例所示,我们甚至不需要去调用_repository.Update(task)方法。
- 异常处理:我们几乎不用在一个使用ABP的Web应用中写异常处理。所有的异常都自动地被默认处理。当一个异常发生,ABP自动记录它并返回一个对应的结果给客户端。例如,一个AJAX请求,它会返回一个Json对象给客户端,告知发生了一个错误。如示例所示,UserFriendlyException可以向客户端隐藏具体的异常,显示友好信息。它同样可以在客户端理解并处理客户端错误,并向用户显示对应的信息。
- 日志:如你所见,我们可以用定义在基类中的Logger对象写日志。默认使用Log4Net,不过这是可修改和可配置的。
- 本地化:请注意我们在抛出异常时,使用了L方法。因此,它可自动依据用户区域,使用相应的本地化信息。当然,我们需要在某处定义CouldNotFoundTheTaskMessage(更多信息参见“本地化”文档)。
- 自动映射:最后一行代码,我们使用ABP的MapTo扩展方法来映射input属性到实体属性。它使用AutoMapper库来执行映射。因此,我们可以简单地基于命名约定,从一个对象映射到另一个。
- 动态Web API 层:实际上TaskAppService是一个简单的类(甚至是不需要从ApplicationService继承)。我们通常包装一个Web API 控制器为Javascript客户端公开方法,ABP会在运行时自动地完成这件事。因此,我们可以直接在客户端使用应用服务。
- 动态Javascript AJAX 代理:ABP创建Javascript代理方法,以便就本地调用一样,来调用应用服务。
通过这么一个简单类我们能看到ABP的便利。完成这些任务一般来说都是很费时的,但是所有的一切,ABP都自动处理了。
除了示例所示,ABP提供了一个强大的基础架构和应用模型,下列为ABP的其它特性:
- 模块化:提供一个强大的基础架构来创建可重用的模块。
- 数据过滤:提供自动地数据过滤来实现一些模式,像软删除和多租户。
- 多租户:完全地支持多租户,包含单数据库或每租户一个单独数据库。
- 设置管理:提供一个基础架构来读取/修改应用、租户和用户级别的设置。
- 单元和集成测试:以可测试为宗旨,当然提供基础类来简化单元测试和集成测试。点击查看更多相关信息。
查看文档了解所有功能。
开始一个新的解决方案、创建层、安装nuget包、创建一个简单的布局和菜单...所有这些都是耗时的工作。
ABP提供预创建的启动模板,使开始一个新的解决方案更简单。模板支持SPA(单页面应用)和MPA(多页面MVC应用)结构。同时允许我们使用不同的ORM工具。
ABP开源项目在Github上,分发在Nuget上。“启动模板”是使用ABP的最简单方式(按文档所述操作)。
kid1412附:英文原文:http://www.aspnetboilerplate.com/Pages/Documents/Introduction