返回总目录


本篇目录

应用服务用于将领域逻辑暴露给展现层。展现层调用具有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理论学习之应用服务的更多相关文章

  1. ABP理论学习之Javascript API(理论完结篇)

    返回总目录 本篇目录 Ajax Notification Message UI block和busy 事件总线 Logging 其他工具功能 说在前面的话 不知不觉,我们送走了2015,同时迎来了20 ...

  2. ABP理论学习之开篇介绍

    返回总目录 为了和2016年春节赛跑,完成该系列博客,我牺牲了今天中午的时间来完成该系列的第一篇----开篇介绍.开篇介绍嘛,读过大学教材的同学都知道,这玩意总是那么无聊,跟考试没关系,干脆直接跳过, ...

  3. ABP理论学习之N层架构

    返回总目录 自从写这个系列博客之后,发现很多园友还是希望有个直接运行的demo,其实在github上就有官方的demo,我直接把这demo的链接放到这里吧,另外,我分析,这些找不到demo的同学,很可 ...

  4. ABP理论学习之依赖注入

    返回总目录 本篇目录 什么是依赖注入 传统方式产生的问题 解决办法 依赖注入框架 ABP中的依赖注入基础设施 注册 解析 其他 ASP.NET MVC和ASP.NET Web API集成 最后提示 什 ...

  5. ABP理论学习之日志记录

    返回总目录 本篇目录 服务端 获取Logger 基类中的Logger 配置 客户端 服务端 ABP使用的是Castle Windsor的日志记录设备.它可以和不同的日志类库一起工作,比如Log4Net ...

  6. ABP理论学习之仓储

    返回总目录 本篇目录 IRepository接口 查询 插入 更新 删除 其他 关于异步方法 仓储实现 管理数据库连接 仓储的生命周期 仓储最佳实践 Martin Fowler对仓储的定义 位于领域层 ...

  7. ABP理论学习之领域服务

    返回总目录 本篇目录 介绍 IDomainService接口和DomainService类 样例 创建一个接口 服务实现 调用应用服务 一些讨论 何不只使用应用服务 如何强制使用领域服务 介绍 领域服 ...

  8. ABP理论学习之工作单元(Unit of Work)

    返回总目录 本篇目录 公共连接和事务管理方法 ABP中的连接和事务管理 仓储类 应用服务 工作单元 工作单元详解 关闭工作单元 非事务的工作单元 工作单元方法调用其它 工作单元作用域 自动保存 IRe ...

  9. ABP理论学习之数据过滤器

    返回总目录 本篇目录 介绍 预定义过滤器 关闭过滤器 开启过滤器 设置过滤器参数 定义自定义过滤器 其他ORM 介绍 软删除模式通常用于不会真正从数据库删除一个实体而是仅仅将它标记为"已删除 ...

随机推荐

  1. MVC 解决 readonly 问题

    <input type="text" class="form-control" name="UR_UserName" value=&q ...

  2. 使用Json Web Token设计Passport系统

    >>Token Auth机制 基于Token的身份验证是无状态的,我们不将用户信息存在服务器或Session中. 相比原始的Cookie+Session方式,更适合分布式系统的用户认证,绕 ...

  3. #英文#品读中国城市个性——秦汉雄风&和祖先在一起

    妨碍 interfere with 仇恨 hatred ​坍塌 collapse 专制君主 autocratic dictator 排除异己 suppress opposition 被逼到绝望边缘 b ...

  4. python 学习第三天

    一,Python的数据结构-集合 1,集合的定义 Python中集合是以{}括起来的,例如x=set({1,2,3,4,5}),这就是一个集合,集合的特点有:(1),去重的(2),无序的,集合的作用用 ...

  5. unity3d关于碰撞问题

    这个是我做忍者游戏出现的问题,做个记录也为以后有人遇到也可以借鉴.因为刚接触unity,所以对其所知甚少,说错的地方请指教. 问题:角色碰撞墙为什么会先触发碰撞地面,然后再触发碰撞墙 想要的效果:是角 ...

  6. dos下对mysql的简单操作(linux类似)

    >>>>>>>>>>>>>>>>>>>> 基础入门语句10条 1. 连接服务器  ...

  7. Tween Animation----Rotate旋转动画

    activity_main.xml布局里 在res/下面新建一个anim文件夹用来保存动画的xml属性 我们在anim文件夹下面创建一个rotate.xml文件 代码如下: <?xml vers ...

  8. python学习6 web开发

    wsgi自带,用语构建简单服务器 例子 from wsgiref.simple_server import make_server def index(env, res): res('200 ok', ...

  9. log4j使用--http://www.cnblogs.com/eflylab/archive/2007/01/11/618001.html

    package log4jTest.com; import java.io.FileReader; import org.apache.log4j.BasicConfigurator; import ...

  10. QuartZ Cron表达式

     Cron Expressions cron的表达式是字符串,实际上是由七子表达式,描述个别细节的时间表.        Seconds        Minutes        Hours     ...