ABP理论学习之应用服务
本篇目录
应用服务用于将领域逻辑暴露给展现层。展现层调用具有DTO参数的应用服务,使用领域对象来执行一些特定的业务逻辑并返回给展现层一个DTO。这样,展现层就完全独立于领域层了。在一个理想的分层应用中,展现层永远不直接和领域对象打交道。
IApplicationService接口###
在ABP中,应用服务应该实现 IApplicationService接口。建议为每个应用服务创建一个接口。这样一来,我们先要为一个应用定义一个接口,如下所示:
public interface IPersonAppService : IApplicationService
{
void CreatePerson(CreatePersonInput input);
}
IPersonAppService只有一个方法。展现层用它来创建一个新的person。CreatePersonInput是如下所示的一个DTO对象:
public class CreatePersonInput : IInputDto
{
[Required]
public string Name { get; set; }
public string EmailAddress { get; set; }
}
然后我可以实现IPersonAppService:
public class PersonAppService : IPersonAppService
{
private readonly IRepository<Person> _personRepository;
public PersonAppService(IRepository<Person> personRepository)
{
_personRepository = personRepository;
}
public void CreatePerson(CreatePersonInput input)
{
var person = _personRepository.FirstOrDefault(p => p.EmailAddress == input.EmailAddress);
if (person != null)
{
throw new UserFriendlyException("There is already a person with given email address");
}
person = new Person { Name = input.Name, EmailAddress = input.EmailAddress };
_personRepository.Insert(person);
}
}
这里是一些重点:
- PersonAppService使用IRepository执行数据库操作。这里使用了依赖注入,而且使用了 构造函数注入的模式。
- PersonAppService实现了IApplicationService,它是通过ABP自动注册到依赖注入系统的,然后被其他的类注入并使用。
- CreatePerson方法以 CreatePersonInput作为参数。它是一个输入DTO,会被ABP自动验证。
ApplicationService类
应用服务类应该实现应用服务接口(IApplicationService)。此外,还可以选择从ApplicationService基类派生。这样,IApplicationService也被继承实现了。而且,ApplicationService有一些基本功能,使得logging和 本土化更加简单。建议为你的继承了ApplicationService的应用服务创建一个特殊的基类。这样,你就可以为所有的应用服务添加一些通用功能。一个应用服务类的例子如下所示:
public class TaskAppService : ApplicationService, ITaskAppService
{
public TaskAppService()
{
LocalizationSourceName = "SimpleTaskSystem";
}
public void CreateTask(CreateTaskInput input)
{
//记录日志 (Logger 定义在 ApplicationService 类中)
Logger.Info("Creating a new task with description: " + input.Description);
//获取本地化文本 (L 是LocalizationHelper.GetString(...)的简写, 定义在 ApplicationService类中)
var text = L("SampleLocalizableTextKey");
//TODO: Add new task to database...
}
}
你可以定义一个基类,在该基类中的构造函数中定义LocalizationSourceName。这样,就不用为所有的服务类重复定义了。
工作单元###
在ABP中,应用服务方法默认是一个工作单元。
数据库连接和事务管理
假如说我们想要在一个必须是事务的应用服务方法中调用两个仓储方法。例如:
public void CreatePerson(CreatePersonInput input)
{
var person = new Person { Name = input.Name, EmailAddress = input.EmailAddress };
_personRepository.Insert(person);
_statisticsRepository.IncrementPeopleCount();
}
我们将一个person实体插入到People表中,然后总人数自增,并保存到另一个表的字段中。这个方法都是用不同的仓储实现的,但是共享了相同的连接和事务。
在CreatePerson方法开始时,ABP会自动打开数据库连接并开始事务。在方法结束时,如果没有异常发生,会自动提交事务并关闭数据库连接。这样,在CreatePerson方法中的所有数据库操作都是事务的(原子的),如果有任何异常抛出,操作就会回滚。因此,在这个方法中的两个仓储共享相同的连接和事务。
当调用仓储的GetAll()方法时,会返回一个IQueryable。数据库连接应该在调用该方法后打开。这是因为IQueryable和Linq会延迟执行。数据库真正查询是在调用 ToList()方法时发生的。看下面的例子:
public SearchPeopleOutput SearchPeople(SearchPeopleInput input)
{
//获得 IQueryable<Person>
var query = _personRepository.GetAll();
//添加过滤
if (!string.IsNullOrEmpty(input.SearchedName))
{
query = query.Where(person => person.Name.StartsWith(input.SearchedName));
}
if (input.IsActive.HasValue)
{
query = query.Where(person => person.IsActive == input.IsActive.Value);
}
//获取分页结果list
var people = query.Skip(input.SkipCount).Take(input.MaxResultCount).ToList();
return new SearchPeopleOutput {People = Mapper.Map<List<PersonDto>>(people)};
}
因为一个应用服务方法是一个工作单元,所以在执行这个方法期间数据库连接是打开的。如果在一个不是应用服务的类中调用了GetAll()方法,那么应该显式使用工作单元。
注意这里使用了AutoMapper类库将 List转成List。更多细节请看下一篇DTO博客。
自动保存更改
对于工作单元方法,ABP会在方法结束时自动保存所有的更改。假设我们有一个更新一个人的名字的应用服务方法:
public void UpdateName(UpdateNameInput input)
{
var person = _personRepository.Get(input.PersonId);
person.Name = input.NewName;
}
只需要这样,name字段就改变了。我们甚至都不要调用_personRepository.Update方法。ORM框架会跟踪工作单元内的实体的所有更改,并将更改反映给数据库。
更多
请查看《工作单元》。
应用服务的生命周期###
所有的应用服务实例都是Transient(每次使用时创建)。ABP强烈建议使用依赖注入技术。当一个应用服务类需要注入时,该类的一个新实例会在依赖注入容器中自动创建。更多内容请查看《依赖注入》。
ABP理论学习之应用服务的更多相关文章
- ABP理论学习之Javascript API(理论完结篇)
返回总目录 本篇目录 Ajax Notification Message UI block和busy 事件总线 Logging 其他工具功能 说在前面的话 不知不觉,我们送走了2015,同时迎来了20 ...
- ABP理论学习之开篇介绍
返回总目录 为了和2016年春节赛跑,完成该系列博客,我牺牲了今天中午的时间来完成该系列的第一篇----开篇介绍.开篇介绍嘛,读过大学教材的同学都知道,这玩意总是那么无聊,跟考试没关系,干脆直接跳过, ...
- ABP理论学习之N层架构
返回总目录 自从写这个系列博客之后,发现很多园友还是希望有个直接运行的demo,其实在github上就有官方的demo,我直接把这demo的链接放到这里吧,另外,我分析,这些找不到demo的同学,很可 ...
- ABP理论学习之依赖注入
返回总目录 本篇目录 什么是依赖注入 传统方式产生的问题 解决办法 依赖注入框架 ABP中的依赖注入基础设施 注册 解析 其他 ASP.NET MVC和ASP.NET Web API集成 最后提示 什 ...
- ABP理论学习之日志记录
返回总目录 本篇目录 服务端 获取Logger 基类中的Logger 配置 客户端 服务端 ABP使用的是Castle Windsor的日志记录设备.它可以和不同的日志类库一起工作,比如Log4Net ...
- ABP理论学习之仓储
返回总目录 本篇目录 IRepository接口 查询 插入 更新 删除 其他 关于异步方法 仓储实现 管理数据库连接 仓储的生命周期 仓储最佳实践 Martin Fowler对仓储的定义 位于领域层 ...
- ABP理论学习之领域服务
返回总目录 本篇目录 介绍 IDomainService接口和DomainService类 样例 创建一个接口 服务实现 调用应用服务 一些讨论 何不只使用应用服务 如何强制使用领域服务 介绍 领域服 ...
- ABP理论学习之工作单元(Unit of Work)
返回总目录 本篇目录 公共连接和事务管理方法 ABP中的连接和事务管理 仓储类 应用服务 工作单元 工作单元详解 关闭工作单元 非事务的工作单元 工作单元方法调用其它 工作单元作用域 自动保存 IRe ...
- ABP理论学习之数据过滤器
返回总目录 本篇目录 介绍 预定义过滤器 关闭过滤器 开启过滤器 设置过滤器参数 定义自定义过滤器 其他ORM 介绍 软删除模式通常用于不会真正从数据库删除一个实体而是仅仅将它标记为"已删除 ...
随机推荐
- js对象克隆方法
方法1: function clone(obj){ var o; switch(typeof obj){ case 'undefined': break; case 'string' : o = ob ...
- 【转】SqlServer将没有log文件的数据库文件附加到服务器中
原文链接: http://www.cnblogs.com/xdotnet/p/attach_sqlserver_database_file_without_log_files.html 原作者删除了原 ...
- sqlserver 查找某个字段在哪张表里
select [name] from [库名].[dbo].sysobjects where id in(select id from [库名].[dbo].syscolumns Where name ...
- python strip()函数 介绍
python strip()函数 介绍,需要的朋友可以参考一下 函数原型 声明:s为字符串,rm为要删除的字符序列 s.strip(rm) 删除s字符串中开头.结尾处,位于 rm删除 ...
- AugularJS特性
AugularJS特性 AngularJS是一个新出现的强大客户端技术,提供给大家的一种开发强大应用的方式.这种方式利用并且扩展HTML,CSS和javascript,并且弥补了它们的一些非常明显的不 ...
- .NET 项目代码风格要求
原文:http://kb.cnblogs.com/page/179593/ 项目代码风格要求 PDF版下载:项目代码风格要求V1.0.pdf 代码风格没有正确与否,重要的是整齐划一,这是我拟的一份&l ...
- 指定eclipse启动使用的JVM
不同eclispe对运行时要求不一样,而一台电脑只能同时使用一个运行时,当多个要求不同版本jvm的eclipse需要在一台电脑工作时,需要手动指定eclipse启动使用的jvm. [eclipse-j ...
- Cucumber(一): Preparation
Every time I wrote some code in ruby and executed our cucumber features I craved for something simil ...
- Linux系统学习优缺点
Linux是一套操作系统,按照鸟哥的说法Linux提供了一个完整的操作系统当中最底层的硬件控制与资源管理的完整架构,这个架构是沿袭Unix良好的传统而来的,功能强大而且稳定性卓越.其实Torvalds ...
- 前端性能优化--为什么DOM操作慢?
作为一个前端,不能不考虑性能问题.对于大多数前端来说,性能优化的方法可能包括以下这些: 减少HTTP请求(合并css.js,雪碧图/base64图片) 压缩(css.js.图片皆可压缩) 样式表放头部 ...