一,一些相关解释

Service 在应用服务层也就是application层。应用服务用于将领域(业务)逻辑暴露给展现层。展现层通过传入DTO(数据传输对象)参数来调用应用服务,而应用服务通过领域对象来执行相应的业务逻辑并且将DTO返回给展现层。

也就是这样避免了应用服务层和展现层的,直接数据交互,而是通过dto实现了数据过滤,这样就可以较好的避免非法数据的传入传出。另外大头还要实现数据隐藏,方便扩展等好处。

创建应用服务时需要注意:

1.service 要实现IApplicationService接口。

2,ABP为IApplicationService提供默认实现ApplicationService

3,ABP中,一个应用服务方法默认是一个工作单元(Unit of Work)。ABP针对UOW模式自动进行数据库的连接及事务管理,且会自动保存数据修改。

二,XXService和IXXService

1,如下TaskAppService 继承了LearningMpaAbpAppServiceBase,并实现了ITaskAppService接口

using Abp.Application.Services.Dto;
using Abp.Authorization;
using Abp.AutoMapper;
using Abp.Domain.Repositories;
using Abp.Events.Bus;
using Abp.Extensions;
using Abp.Linq.Extensions;
using Abp.Net.Mail.Smtp;
using Abp.Notifications;
using Abp.Runtime.Session;
using AutoMapper;
using LearningMpaAbp.Authorization;
using LearningMpaAbp.Authorization.Users;
using LearningMpaAbp.Tasks.Dtos;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks; namespace LearningMpaAbp.Tasks
{
/// <summary>
/// Implements <see cref="ITaskAppService" /> to perform task related application functionality.
/// Inherits from <see cref="ApplicationService" />.
/// <see cref="ApplicationService" /> contains some basic functionality common for application services (such as
/// logging and localization).
/// </summary>
public class TaskAppService : LearningMpaAbpAppServiceBase, ITaskAppService
{
private readonly INotificationPublisher _notificationPublisher;
private readonly ISmtpEmailSender _smtpEmailSender;
//These members set in constructor using constructor injection. private readonly IRepository<Task> _taskRepository;
private readonly IRepository<User, long> _userRepository;
private readonly ITaskManager _taskManager;
private readonly ITaskCache _taskCache;
private readonly IEventBus _eventBus; /// <summary>
/// In constructor, we can get needed classes/interfaces.
/// They are sent here by dependency injection system automatically.
/// </summary>
public TaskAppService(
IRepository<Task> taskRepository,
IRepository<User, long> userRepository,
ISmtpEmailSender smtpEmailSender,
INotificationPublisher notificationPublisher,
ITaskCache taskCache,
ITaskManager taskManager,
IEventBus eventBus)
{
_taskRepository = taskRepository;
_userRepository = userRepository;
_smtpEmailSender = smtpEmailSender;
_notificationPublisher = notificationPublisher;
_taskCache = taskCache;
_taskManager = taskManager;
_eventBus = eventBus;
} public TaskCacheItem GetTaskFromCacheById(int taskId)
{
return _taskCache[taskId];
} public IList<TaskDto> GetAllTasks()
{
var tasks = _taskRepository.GetAll().OrderByDescending(t => t.CreationTime).ToList();
return Mapper.Map<IList<TaskDto>>(tasks);
} public GetTasksOutput GetTasks(GetTasksInput input)
{
var query = _taskRepository.GetAllIncluding(t => t.AssignedPerson)
.WhereIf(input.State.HasValue, t => t.State == input.State.Value)
.WhereIf(!input.Filter.IsNullOrEmpty(), t => t.Title.Contains(input.Filter))
.WhereIf(input.AssignedPersonId.HasValue, t => t.AssignedPersonId == input.AssignedPersonId.Value); //排序
if (!string.IsNullOrEmpty(input.Sorting))
query = query.OrderBy(input.Sorting);
else
query = query.OrderByDescending(t => t.CreationTime); var taskList = query.ToList(); //Used AutoMapper to automatically convert List<Task> to List<TaskDto>.
return new GetTasksOutput
{
Tasks = Mapper.Map<List<TaskDto>>(taskList)
};
} public PagedResultDto<TaskDto> GetPagedTasks(GetTasksInput input)
{
//初步过滤
var query = _taskRepository.GetAllIncluding(t => t.AssignedPerson)
.WhereIf(input.State.HasValue, t => t.State == input.State.Value)
.WhereIf(!input.Filter.IsNullOrEmpty(), t => t.Title.Contains(input.Filter))
.WhereIf(input.AssignedPersonId.HasValue, t => t.AssignedPersonId == input.AssignedPersonId.Value); //排序
query = !string.IsNullOrEmpty(input.Sorting) ? query.OrderBy(input.Sorting) : query.OrderByDescending(t => t.CreationTime); //获取总数
var tasksCount = query.Count();
//默认的分页方式
//var taskList = query.Skip(input.SkipCount).Take(input.MaxResultCount).ToList(); //ABP提供了扩展方法PageBy分页方式
var taskList = query.PageBy(input).ToList(); return new PagedResultDto<TaskDto>(tasksCount, taskList.MapTo<List<TaskDto>>());
} public async Task<TaskDto> GetTaskByIdAsync(int taskId)
{
//Called specific GetAllWithPeople method of task repository.
var task = await _taskRepository.GetAsync(taskId); //Used AutoMapper to automatically convert List<Task> to List<TaskDto>.
return task.MapTo<TaskDto>();
} public TaskDto GetTaskById(int taskId)
{
var task = _taskRepository.Get(taskId); return task.MapTo<TaskDto>();
} public void UpdateTask(UpdateTaskInput input)
{
//We can use Logger, it's defined in ApplicationService base class.
Logger.Info("Updating a task for input: " + input); //获取是否有权限
bool canAssignTaskToOther = PermissionChecker.IsGranted(PermissionNames.Pages_Tasks_AssignPerson);
//如果任务已经分配且未分配给自己,且不具有分配任务权限,则抛出异常
if (input.AssignedPersonId.HasValue && input.AssignedPersonId.Value != AbpSession.GetUserId() &&
!canAssignTaskToOther)
{
throw new AbpAuthorizationException("没有分配任务给他人的权限!");
} var updateTask = Mapper.Map<Task>(input);
var user = _userRepository.Get(input.AssignedPersonId.Value);
//先执行分配任务
_taskManager.AssignTaskToPerson(updateTask, user); //再更新其他字段
_taskRepository.Update(updateTask); } public void AssignTaskToPerson(AssignTaskToPersonInput input)
{
var task = _taskRepository.Get(input.TaskId);
var user = _userRepository.Get(input.UserId);
_taskManager.AssignTaskToPerson(task, user);
//这里有一个问题就是,当开发人员不知道有这个TaskManager时,依然可以通过直接修改Task的AssignedPersonId属性就行任务分配。 //分配任务成功后,触发领域事件,发送邮件通知
//_eventBus.Trigger(new TaskAssignedEventData(task, user));//由领域服务触发领域事件 } public int CreateTask(CreateTaskInput input)
{
//We can use Logger, it's defined in ApplicationService class.
Logger.Info("Creating a task for input: " + input); //判断用户是否有权限
if (input.AssignedPersonId.HasValue && input.AssignedPersonId.Value != AbpSession.GetUserId())
PermissionChecker.Authorize(PermissionNames.Pages_Tasks_AssignPerson); var task = Mapper.Map<Task>(input); int result = _taskRepository.InsertAndGetId(task); //只有创建成功才发送邮件和通知
if (result > 0)
{
if (input.AssignedPersonId.HasValue)
{
var user = _userRepository.Load(input.AssignedPersonId.Value);
//task.AssignedPerson = user;
//var message = "You hava been assigned one task into your todo list."; //使用领域事件触发发送通知操作
_eventBus.Trigger(new TaskAssignedEventData(task, user)); //TODO:需要重新配置QQ邮箱密码
//_smtpEmailSender.Send("ysjshengjie@qq.com", task.AssignedPerson.EmailAddress, "New Todo item", message); //_notificationPublisher.Publish("NewTask", new MessageNotificationData(message), null,
// NotificationSeverity.Info, new[] { task.AssignedPerson.ToUserIdentifier() });
}
} return result;
} public void Delete(int id)
{
var task = _taskRepository.Get(id);
if (task != null)
_taskRepository.Delete(task);
}
}
}

2,ITaskAppService 继承IApplicationService

using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic;
using System.Threading.Tasks;
using Abp.Application.Services;
using Abp.Application.Services.Dto;
using Abp.Linq.Extensions;
using LearningMpaAbp.Tasks.Dtos; namespace LearningMpaAbp.Tasks
{
public interface ITaskAppService : IApplicationService
{
GetTasksOutput GetTasks(GetTasksInput input); PagedResultDto<TaskDto> GetPagedTasks(GetTasksInput input); void UpdateTask(UpdateTaskInput input); int CreateTask(CreateTaskInput input); Task<TaskDto> GetTaskByIdAsync(int taskId); TaskDto GetTaskById(int taskId); void Delete(int taskId); TaskCacheItem GetTaskFromCacheById(int taskId); IList<TaskDto> GetAllTasks();
}
}

三,Dto 数据传输对象(Data Transfer Objects)用于应用层和展现层的数据传输

ABP 建议命名 input/ouput 对象类似于 MethodNameInput/MethodNameOutput,对于每个应用服务方法都需要将 Input 和 Output 进行分开定义。甚至你的方法只接
收或者返回一个值,也最好创建相应的 DTO 类型。 这样会使代码有更好的扩展性

using System.Collections.Generic;

namespace LearningMpaAbp.Tasks.Dtos
{
public class GetTasksOutput
{
public List<TaskDto> Tasks { get; set; }
}
}

有一个问题怎么将task实体类转换为dto,这时就需要进行映射了AutoMapper 根据 Task实体创建了 taskDto,并根据命名约定来给
PersonDto 的属性赋值 。

以上。。

参考:http://www.jianshu.com/p/da69ca7b27c6

代码:https://github.com/tianxiangd/LearnAbp

ABP学习入门系列(四)(创建Service)的更多相关文章

  1. ABP学习入门系列(六)(菜单和分页)

    1,菜单.在最新的abp3.1.2中 菜单栏是在左侧的如下图(上中下的结构),中间部分就是我们要添加菜单的地方. ABP集成了通用的创建和显示菜单的方式,在展示层web下的appstart文件夹下找到 ...

  2. ABP学习入门系列(三) (领域层中的仓储Repository)

    一,仓储定义:“在领域层和数据映射层的中介,使用类似集合的接口来存取领域对象”(Martin Fowler) . 仓储用来操作数据库进行数据存取.仓储接口在领域层定义,而仓储的实现类应该写在基础设施层 ...

  3. ABP学习入门系列(一)(第一个ABP项目)

    ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称.ASP.NET Boilerplate是一个用最佳实践和流行技术开发现代WEB应用程序的新起点,它 ...

  4. ABP学习入门系列(五)(展示实现增删改查)

    大致要实现的 效果如下 1,添加Controller(用到的X.PagedList 注意到nuget添加) using System.Web.Mvc; using Abp.Application.Se ...

  5. ABP学习入门系列(二)(abp的数据迁移)

    本文将介绍在ABP框架中将实体类迁移至数据库表 1.下图是abp的体系结构. 我们要是实现创建实体类并迁移数据到数据库的功能主要就是在下图中domain(领域层)做相应的一些操作. 2,看一下解决方案 ...

  6. OPEN(SAP) UI5 学习入门系列之四:更好的入门系列-官方Walkthrough

    好久没有更新了,实在不知道应该写一些什么内容,因为作为入门系列,实际上应该更多的是操作而不是理论,而在UI5 SDK中的EXPLORER里面有着各种控件的用法,所以在这里也没有必要再来一遍,还是看官方 ...

  7. OPEN(SAP) UI5 学习入门系列之一:扫盲与热身(下)

    1 UI5代码结构 上一次我们一起用了20秒的时间完成一个UI5版的Hello World.应用打开后有一个按钮,按钮的文字是Hello World,点击这个按钮之后,按钮会慢慢的消失掉(Fade o ...

  8. C语言高速入门系列(四)

    C语言高速入门系列(四) C语言数组 ---------转载请注明出处:coder-pig 贴心小提示:假设图看不清晰可右键另存为,应该就非常清晰了; 注意上面的代码都要自己过一遍哦! 本节引言: 经 ...

  9. 6. oracle学习入门系列之六 模式

    oracle学习入门系列之六 模式 上篇咱们学习记录了ORACLE数据库中的数据库结构.内存结构和进程等.篇幅 蛤蟆感觉偏多了.这次要休整下,每次笔记不宜太多,不然与书籍有何差别. 我们要保证的是每次 ...

随机推荐

  1. RabbitMQ基础入门篇

    下载安装 Erlang RabbitMQ 启动RabbitMQ管理平台插件 DOS下进入到安装目录\sbin,执行以下命令 rabbitmq-plugins enable rabbitmq_manag ...

  2. Font Awesome矢量版,十六进制版,WPF字体使用

    我之前在博客中介绍过几个矢量图库网站,在WPF程序中,一般接触到的矢量图标资源有XAML.SVG.字体这三种格式.XAML是标准格式就不说了,SVG并不是直接支持的,不过微软提供了Expression ...

  3. Javascript/jQuery常用方法

    //字符串转成时间 function getDate(strDate) { var date = eval('new Date(' + strDate.replace(/\d+(?=-[^-]+$)/ ...

  4. Linux中目录proc/net/dev详解

    在Linux系统中,系统调用是操作系统提供给应用程序使用操作系统服务的重要接口,但同时也正是通过系统调用机制,操作系统屏蔽了用户直接访问系统内核的可能性.幸运的是Linux提供了LKM机制可以使我们在 ...

  5. Day 11 函数名,闭包,装饰器. +作业

    '''一.函数名.def func(): print(5555)print(func)#输出结果 <function func at 0x026B5E88> 打印函数地址. # 1. 函数 ...

  6. 646. Maximum Length of Pair Chain

    You are given n pairs of numbers. In every pair, the first number is always smaller than the second ...

  7. 推荐算法之 slope one 算法

    1.示例引入 多个吃货在某美团的某家饭馆点餐,如下两道菜: 可乐鸡翅: 红烧肉: 顾客吃过后,会有相关的星级评分.假设评分如下: 评分 可乐鸡翅 红烧肉 小明 4 5 小红 4 3 小伟 2 3 小芳 ...

  8. class字节码结构(二)(访问标志、类索引、父类索引、接口索引集合)

    <Java虚拟机原理图解>1.3.class文件中的访问标志.类索引.父类索引.接口索引集合 字节码总体结构: 访问标志(access_flags)能够表示什么? 访问标志(access_ ...

  9. 如何解决liunx链接远程数据库10038错误提示

    关于在windows下链接liunx系统下远程数据库报错2003--提示10038的解决方案如下: 在liunx系统中安装配置mysql数据库默认是没有对外开启3600端口,如果出现10038: 1, ...

  10. 【codeforces 623E】dp+FFT+快速幂

    题目大意:用$[1,2^k-1]$之间的证书构造一个长度为$n$的序列$a_i$,令$b_i=a_1\ or\ a_2\ or\ ...\ or a_i$,问使得b序列严格递增的方案数,答案对$10^ ...