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 介绍 软删除模式通常用于不会真正从数据库删除一个实体而是仅仅将它标记为"已删除 ...
随机推荐
- Android 笔记 a+b day6
独立写了自己第一个Android app -----------a+b!!!!! 自己手机Android版本4.2太低,安装时会出现解析失败,装到室友手机上就好了~~ happy~~ package ...
- PROC 文件系统调节参数介绍(netstat -us)
转自:http://www.cnblogs.com/super-king/p/3296333.html /proc/net/* snmp文件 Ip: ip项 Forwarding : 是 ...
- CollectionView水平和竖直瀑布流的实现
最近在项目中需要实现一个水平的瀑布流(即每个Cell的高度是固定的,但是长度是不固定的),因为需要重写系统 UICollectionViewLayout中的一些方法通过计算去实现手动布局,所以本着代码 ...
- ABP集合贴(转)
ABP集合贴 本文背景 公司最近规划的新框架准备基于ABP来搭建,自从在阳铭博客看到ABP框架的介绍后,就一直持续关注着,但还没真正在实际项目中直接使用ABP,只是自己做了一些学习和Demo.ABP所 ...
- iOS Hit-Test应用
最近又看了遍苹果的官方文档<Event Handling Guide for iOS>,对事件响应链中的hit-test view 又多了些理解,个人觉的官方文档对这块讲的非常简单,很多东 ...
- SOAPUI使用教程-REST服务和WADL
首先创建一个新的REST项目: 选择文件|新建项目REST从主菜单: 通常情况下,我们可能会只提供一个URI 点击导入消耗. 在新建项目消耗对话框: 点击浏览. 然后,我们可以浏览到该文件: 点击 ...
- 【生活没有希望】poj1273网络流大水题
你不能把数据规模改大点吗= =我优化都不加都过了 #include <cstdio> #define INF 2147483647 int n,m,ans,x,y,z,M; ],l[],f ...
- [BZOJ4199][NOI2015]品酒大会
#131. [NOI2015]品酒大会 统计 描述 提交 自定义测试 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个奖项, ...
- Thinkphp3.2.3 执行query命令 包括在模板中使用<php> </php>时 query的使用方法
$sql="select * from `rjshop_productbase` where `id`=1"; $Model =M();$query=$Model->quer ...
- oracle表空间简单学习
1.重命名表空间:alter tablespace 原表空间名 rename to 新表空间名ps:(1)system 和sysaux表空间不能重名(2)如果该表空间中任何一个数据出于脱机状态或者表空 ...