abp.NET core)+easyui+efcore 仓储系统目录
abp.NET core)+easyui+efcore 仓储系统 --ABP 总体介绍(一)
abp.NET core)+easyui+efcore 仓储系统 -- 解决方案介绍(二)
abp.NET core)+easyui+efcore 仓储系统 -- 领域层创建实体(三)
abp.NET core)+easyui+efcore 仓储系统 -- 定义仓储并实现 (四)
在上一篇文章中学习了 ABP 的仓储 (Repository) 功能, Repository 对数据库进行增删改查操作. 在这一篇文章中我们主要了解应用服务层.
一, 解释下应用服务层
应用服务用于将领域 (业务) 逻辑暴露给展现层. 展现层通过传入 DTO(数据传输对象)参数来调用应用服务, 而应用服务通过领域对象来执行相应的业务逻辑并且将 DTO 返回给展现层. 因此, 展现层和领域层将被完全隔离开来.
以下几点, 在创建应用服务时需要注意:
在 ABP 中, 一个应用服务需要实现 IApplicationService 接口, 最好的实践是针对每个应用服务都创建相应继承自 IApplicationService 的接口.(通过继承该接口, ABP 会自动帮助依赖注入)
ABP 为 IApplicationService 提供了默认的实现 ApplicationService, 该基类提供了方便的日志记录和本地化功能. 实现应用服务的时候继承自 ApplicationService 并实现定义的接口即可.
ABP 中, 一个应用服务方法默认是一个工作单元(Unit of Work).ABP 针对 UOW 模式自动进行数据库的连接及事务管理, 且会自动保存数据修改.
二, 定义应用服务接口需要用到的 DTO
1. 在 Visual Studio 2017 的 "解决方案资源管理器" 中, 右键单击 "ABP.TPLMS.Application" 项目. 选择 "添加"> "新建文件夹".
2.将文件夹命名为 "Modules".
3. 右键单击 "Modules" 文件夹, 选择 "添加"> "新建文件夹". 将文件夹重命名为 "Dto". 如下图.
4. 右键单击 "Dto" 文件夹, 然后选择 "添加"> "类". 将类命名为 ModuleDto, 然后选择 "添加". 代码如下.
- using Abp.Application.Services.Dto;
- using Abp.AutoMapper;
- using ABP.TPLMS.Entitys;
- using System;
- using System.Collections.Generic;
- using System.Text;
- namespace ABP.TPLMS.Modules.Dto
- {
- [AutoMapFrom(typeof(Module))]
- public class ModuleDto:EntityDto<long>
- {
- public string DisplayName { get; set; }
- public string Name { get; set; }
- public string Url { get; set; }
- public string HotKey { get; set; }
- public int ParentId { get; set; }
- public bool RequiresAuthentication { get; set; }
- public bool IsAutoExpand { get; set; }
- public string IconName { get; set; }
- public int Status { get; set; }
- public string ParentName { get; set; }
- public string RequiredPermissionName { get; set; }
- public int SortNo { get; set; }
- }
- }
为了在页面上展示模块信息, ModuleDto 被用来将模块数据传递到基础设施层.
ModuleDto 继承自 EntityDto<long>. 跟在领域层定义的 Module 类一样具有一些相同属性.
[AutoMapFrom(typeof(Module))]
用来创建从 Module 类到 ModuleDto 的映射. 使用这种方法. 你可以将 Module 对象自动转换成 ModuleDto 对象(而不是手动复制所有的属性).
5. 右键单击 "Dto" 文件夹, 然后选择 "添加"> "类". 将类命名为 CreateUpdateModuleDto, 然后选择 "添加". 代码如下.
- using Abp.Application.Services.Dto;
- using System;
- using System.Collections.Generic;
- using System.ComponentModel.DataAnnotations;
- using System.Text;
- namespace ABP.TPLMS.Modules.Dto
- {
- public class CreateUpdateModuleDto : EntityDto<long>
- {
- public const int MaxLength = 255;
- [Required]
- [StringLength(MaxLength)]
- public string DisplayName { get; set; }
- [Required]
- [StringLength(MaxLength)]
- public string Name { get; set; }
- [Required]
- [StringLength(MaxLength)]
- public string Url { get; set; }
- [StringLength(MaxLength)]
- public string HotKey { get; set; }
- public int ParentId { get; set; }
- public bool RequiresAuthentication { get; set; }
- public bool IsAutoExpand { get; set; }
- [StringLength(MaxLength)]
- public string IconName { get; set; }
- public int Status { get; set; }
- [Required]
- [StringLength(MaxLength)]
- public string ParentName { get; set; }
- [StringLength(MaxLength)]
- public string RequiredPermissionName { get; set; }
- public int SortNo { get; set; }
- }
- }
这个 DTO 类在创建和更新模块信息的时候被使用, 用来从页面获取模块信息.
类中的属性定义了数据注解 (如[Required]) 用来定义有效性验证. ABP 会自动校验 DTO 的数据有效性.
6. 为什么需要通过 dto 进行数据传输?
一般来说, 使用 DTO 进行数据传输具有以下好处.
数据隐藏
序列化和延迟加载问题
ABP 对 DTO 提供了约定类以支持验证
参数或返回值改变, 通过 Dto 方便扩展
DTO 类被用来在 基础设施层 和 应用层 传递数据.
7.Dto 规范 (灵活应用)
ABP 建议命名输入 / 输出参数为: MethodNameInput 和 MethodNameOutput
并为每个应用服务方法定义单独的输入和输出 DTO(如果为每个方法的输入输出都定义一个 dto, 那将有一个庞大的 dto 类需要定义维护. 一般通过定义一个公用的 dto 进行共用)
即使你的方法只接受 / 返回一个参数, 也最好是创建一个 DTO 类
一般会在对应实体的应用服务文件夹下新建 Dtos 文件夹来管理 Dto 类.
定义完 DTO, 是不是脑袋有个疑问, 我在用 DTO 在展现层与应用服务层进行数据传输, 但最终这些 DTO 都需要转换为实体才能与数据库直接打交道啊. 如果每个 dto 都要自己手动去转换成对应实体, 这个工作量也是不可小觑啊.
聪明如你, 你肯定会想肯定有什么方法来减少这个工作量.
三, 使用 AutoMapper 自动映射 DTO 与实体
1. 简要介绍 AutoMapper
开始之前, 如果对 AutoMapper 不是很了解, 建议看下这篇文章 AutoMapper 小结.
AutoMapper 的使用步骤, 简单总结下:
创建映射规则(Mapper.CreateMap<source, destination>();)
类型映射转换(Mapper.Map<source,destination>(sourceModel))
在 Abp 中有两种方式创建映射规则:
特性数据注解方式:
AutoMapFrom,AutoMapTo 特性创建单向映射
AutoMap 特性创建双向映射
代码创建映射规则:
Mapper.CreateMap<source, destination>();
2. 为 Module 实体相关的 Dto 定义映射规则
ModuleDto,CreateUpdateModuleDto 中的属性名与 Module 实体的属性命名一致, 且只需要从 Dto 映射到实体, 不需要反向映射. 所以通过 AutoMapTo 创建单向映射即可.
- [AutoMapTo(typeof(Module))] // 定义单向映射
- public class ModuleDto:EntityDto<long>
- {
- ...
- }
- [AutoMapTo(typeof(Module))] // 定义单向映射
- public class CreateUpdateModuleDto : EntityDto<long>
- {
- ...
- }
四, 定义 IModuleAppService 接口
1. 右键单击 "Dto" 文件夹, 然后选择 "添加"> "新建项", 在弹出对话框中选择 "接口". 为应用服务定义一个名为 IModuleAppService 的接口. 代码如下.
- using Abp.Application.Services;
- using Abp.Application.Services.Dto;
- using ABP.TPLMS.Modules.Dto;
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Threading.Tasks;
- namespace ABP.TPLMS.Modules
- {
- public interface IModuleAppService : IApplicationService
- {
- Task CreateAsync(CreateUpdateModuleDto input);
- Task UpdateAsync(CreateUpdateModuleDto input);
- Task<ListResultDto<ModuleDto>> GetAllAsync();
- Task DeleteAsync(int Id);
- void Delete(int Id);
- }
- }
从上面的代码中我们仔细看一下方法的参数及返回值, 大家可能会发现并未直接使用 Module 实体对象. 这是为什么呢? 因为展现层与应用服务层是通过 Data Transfer Object(DTO)进行数据传输.
五, 实现 IModuleAppService
对于具体的业务来讲, 只是简单的增删该查, 实现起来就很简单了. 代码如下:
- using Abp.Application.Services;
- using Abp.Application.Services.Dto;
- using Abp.Domain.Repositories;
- using ABP.TPLMS.Entitys;
- using ABP.TPLMS.Modules.Dto;
- using AutoMapper;
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Threading.Tasks;
- namespace ABP.TPLMS.Modules
- {
- public class ModuleAppService : ApplicationService, IModuleAppService
- {
- private readonly IRepository<Module> _moduleRepository;
- public ModuleAppService(IRepository<Module> moduleRepository)
- {
- _moduleRepository = moduleRepository;
- }
- public Task CreateAsync(CreateUpdateModuleDto input)
- {
- var module = Mapper.Map<Module>(input);
- return _moduleRepository.InsertAsync(module);
- }
- public Task UpdateAsync(CreateUpdateModuleDto input)
- {
- var module = Mapper.Map<Module>(input);
- return _moduleRepository.UpdateAsync(module);
- }
- public async Task<ListResultDto<ModuleDto>> GetAllAsync()
- {
- var books = await _moduleRepository.GetAllListAsync();
- return new ListResultDto<ModuleDto>(ObjectMapper.Map<List<ModuleDto>>(books));
- }
- public async Task DeleteAsync(int Id)
- {
- await _moduleRepository.DeleteAsync(Id);
- }
- public void Delete(int Id)
- {
- _moduleRepository.Delete(Id);
- }
- }
- }
来源: https://www.cnblogs.com/chillsrc/p/11065667.html