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层规范

400

  1. Services项目的命名规范是XXX.Services,XXX为所属领域,注意一定是.Services结尾(否则可能出现自动注入失败的情况)
  2. 在对应领域Service的文件夹下,需要包含三个项目,分别是XXX.ContractXXX.DtoXXX.Services
  3. 对应具体服务需要继承对应契约

    public class AccessPartyService : IAccessPartyService
    {
     ...
    }
    
  4. Services层属于业务层,目前可以处理由Controller层接收的Request参数,返回Dto类,同时Services层可以获取通过仓储层Repository处理好的DB数据(Entity、MappingData),进行业务聚合处理。不允许Services层去newController下的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

results matching ""

    No results matching ""