BusinessServices 业务契约与服务
请在对应Services层项目中引入Aegis.Services
的Nuget包(框架版本须2.0+)
启用BusinessServices
在Component.deps.json
中的Services节点中确定包含了BusinessServices
。
Contract 契约
契约是服务的接口层,目前Contract这一层里只需要将定义服务的接口就行。
注意,服务的契约层接口都需要继承IBusinessService
/// <summary>
/// 访问方服务契约
/// </summary>
public interface IAccessPartyService : IBusinessService
{
/// <summary>
/// 获取访问方列表
/// </summary>
/// <param name="reqDto"></param>
/// <returns></returns>
Task<PagedResult<GetAccessPartyDto>> GetAccessPartyListByPage(GetAccessPartyListRequest request);
...
}
Services层规范
- Services项目的命名规范是XXX.Services,XXX为所属领域,注意一定是
.Services
结尾(否则可能出现自动注入失败的情况) - 在对应领域Service的文件夹下,需要包含三个项目,分别是
XXX.Contract
、XXX.Dto
和XXX.Services
对应具体服务需要继承对应契约
public class AccessPartyService : IAccessPartyService { ... }
Services层属于业务层,目前可以处理由Controller层接收的Request参数,返回Dto类,同时Services层可以获取通过仓储层Repository处理好的DB数据(Entity、MappingData),进行业务聚合处理。不允许Services层去
new
Controller下的Request类。
PagedResult
PagedResult是用于查询分页数据服务的响应结果。 他的具体实现是结构体类型,故不推荐用于传递给其他服务方法,建议只在返回Controller层的时候使用该类型。
[Serializable]
[StructLayout(LayoutKind.Auto)]
public readonly struct PagedResult<T> : IEquatable<PagedResult<T>>
{
public List<T> Entities { get; init; }
public long Total { get; init; }
public int CurrentIndex { get; init; }
public int PageSize { get; init; }
public PagedResult(List<T> entities, long total, int currentIndex, int pageSize)
{
Entities = entities;
Total = total;
CurrentIndex = currentIndex;
PageSize = pageSize;
}
}
Services下的分页和快速转换
出于层次隔离的考虑,Repository
层下PagedList
并不能直接用在Services层下。而Services提供了PagedResult
结果作为这一层的分页返回结构。
DtoPaged<T>.Convert
可以将传进来的list直接转换为PagedResult
。通过泛型Type传入对应的Dto类型,Convert会Entity实体通过Adpter
映射到Dto类
。
var list = _ipVisitRepository.GetRyIpVisitList(filter);
return DtoPaged<GetRyIpVisitListDto>.Convert(list);
如果不需要Mapping则使用DtoPaged<GetRyIpVisitListDto>.Convert(list,false);
,默认情况是会将传入的类型映射到对应的泛型类型,如果无法映射会出现错误结果。请确保该Entity能正确映射到对应的DTO类型。
ServiceResult
Services层下的服务尽量直接返回处理好的类型(Dto、List、int、bool等等);只有复杂业务流程有多种分支结果的情况下才建议使用ServiceResult
。
方法名 | 说明 | 提供版本 |
---|---|---|
ServiceResult.Success | 服务成功,正常返回 | 1.04 |
ServiceResult.Failed | 失败结果,业务失败或者业务验证错误使用 | 1.04 |
ServiceResult.Error | 异常结果,建议在业务中,Catch到异常的时候使用 | 1.07 |
错误示范
/// <summary>
/// 创建接入方
/// </summary>
/// <param name="AccessPartyDto"></param>
/// <returns></returns>
public async Task<ServiceResult<bool>> CreateAccessParty(CreateAccessPartyRequest request)
{
var accessParty = request.Adapt<AccessPartyEntity>();
accessParty.AppId = getAppId();
accessParty.AppSecret = getAppSecret(accessParty.AppId);
var result = await _db.Insert(accessParty).ExecuteAffrowsAsync() > 0;
return ServiceResult.Success(MessageType.Message, result ? "操作成功!" : "操作失败!", result);
}
正确示范 像常规可以直接返回的bool、List、PagedList、xxxDto都可以直接返回
/// <summary>
/// 创建接入方
/// </summary>
/// <param name="AccessPartyDto"></param>
/// <returns></returns>
public async Task<bool> CreateAccessParty(CreateAccessPartyRequest request)
{
var accessParty = request.Adapt<AccessPartyEntity>();
accessParty.AppId = getAppId();
accessParty.AppSecret = getAppSecret(accessParty.AppId);
return await _db.Insert(accessParty).ExecuteAffrowsAsync() > 0;
}
复杂业务示范
需要判断多种业务的情况下才建议使用ServiceResult
/// <summary>
/// 根据seq获取身份信息
/// </summary>
/// <param name="VisitPayTypeSeq">主键</param>
/// <returns></returns>
public async Task<ServiceResult<VisitPayTypeDto>> GetVisitPayTypeBySeq(long VisitPayTypeSeq)
{
if (VisitPayTypeSeq <= 0)
{
return ServiceResult.Failed<VisitPayTypeDto>(MessageType.Notice, $"获取身份信息失败,入参错误");
}
var data = await _visitPayTypeRepository.Where(o => !o.IsDeleted && o.VisitPayTypeSeq == VisitPayTypeSeq).FirstAsync();
if (data == null)
{
return ServiceResult.Failed<VisitPayTypeDto>(MessageType.Notice, $"获取身份信息失败,未能查询到信息");
}
var result = data.Adapt<VisitPayTypeDto>();
return ServiceResult.Success(MessageType.Ignore, $"获取身份信息成功", result);
}
ServiceResult.Error
使用方法
try
{
//业务代码
...
}
catch (Exception ex)
{
return ServiceResult.Error<BoSiElecIssueResponse>(ex, $"{ReceiptNo}:开票异常");
}
ServiceResult.Error
本质上就是将异常包含进BusinessException
,并throw
出来,最终由框架捕获异常并处理和记录。
这条方法会直接中断当前请求(因为本质上就是throw出异常)
public static ServiceResult<T> Error<T>(Exception exception, string message)
{
throw new BusinessException(message,exception);
}
如果不想中断当前请求,且想记录当前异常,请使用日志组件记录异常信息,再进行操作,如果要返回错误结果则在记录完日志后使用ServiceResult.Failed
。