上一篇文章(https://www.cnblogs.com/meowv/p/12916613.html)使用自定义仓储完成了简单的增删改查案例,有心的同学可以看出,我们的返回参数一塌糊涂,显得很不友好。
在实际开发过程中,每个公司可能不尽相同,但都大同小异,我们的返回数据都是包裹在一个公共的模型下面的,而不是直接返回最终数据,在返回参数中,显示出当前请求的时间戳,是否请求成功,如果错误那么错误的消息是什么,状态码(状态码可以是我们自己定义的值)等等。可能显得很繁琐,没必要,但这样做的好处毋庸置疑,除了美化了我们的API之外,也方便了前端同学的数据处理。
我们将统一的返回模型放在.ToolKits层中,之前说过这里主要是公共的工具类、扩展方法。
新建一个Base文件夹,添加响应实体类ServiceResult.cs,在Enum文件夹下单独定义一个ServiceResultCode响应码枚举,0/1。分别代表 成功和失败。
//ServiceResultCode.cs namespace Meowv.Blog.ToolKits.Base.Enum { /// <summary> /// 服务层响应码枚举 /// </summary> public enum ServiceResultCode { /// <summary> /// 成功 /// </summary> Succeed = 0, /// <summary> /// 失败 /// </summary> Failed = 1, } } //ServiceResult.cs using Meowv.Blog.ToolKits.Base.Enum; using System; namespace Meowv.Blog.ToolKits.Base { /// <summary> /// 服务层响应实体 /// </summary> public class ServiceResult { /// <summary> /// 响应码 /// </summary> public ServiceResultCode Code { get; set; } /// <summary> /// 响应信息 /// </summary> public string Message { get; set; } /// <summary> /// 成功 /// </summary> public bool Success => Code == ServiceResultCode.Succeed; /// <summary> /// 时间戳(毫秒) /// </summary> public long Timestamp { get; } = (DateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000; /// <summary> /// 响应成功 /// </summary> /// <param></param> /// <param></param> /// <returns></returns> public void IsSuccess(string message = "") { Message = message; Code = ServiceResultCode.Succeed; } /// <summary> /// 响应失败 /// </summary> /// <param></param> /// <param></param> /// <returns></returns> public void IsFailed(string message = "") { Message = message; Code = ServiceResultCode.Failed; } /// <summary> /// 响应失败 /// </summary> /// <paramdata"></param> /// <returns></returns> public void IsFailed(Exception exception) { Message = exception.InnerException?.StackTrace; Code = ServiceResultCode.Failed; } } }可以看到,还定义了 string 类型的 Message,bool 类型的 Success,Success取决于Code == ServiceResultCode.Succeed的结果。还有一个当前的时间戳Timestamp。
其中还有IsSuccess(...)和IsFailed(...)方法,当我们成功返回数据或者当系统出错或者参数异常的时候执行,这一点也不难理解吧。
这个返回模型暂时只支持无需返回参数的api使用,还需要扩展一下,当我们需要返回其它各种复杂类型的数据就行不通了。所以还需要添加一个支持泛型的返回模型,新建模型类:ServiceResultOfT.cs,这里的T就是我们的返回结果,然后继承我们的ServiceResult,指定T为class。并重新编写一个IsSuccess(...)方法,代码如下:
//ServiceResultOfT.cs using Meowv.Blog.ToolKits.Base.Enum; namespace Meowv.Blog.ToolKits.Base { /// <summary> /// 服务层响应实体(泛型) /// </summary> /// <typeparam></typeparam> public class ServiceResult<T> : ServiceResult where T : class { /// <summary> /// 返回结果 /// </summary> public T Result { get; set; } /// <summary> /// 响应成功 /// </summary> /// <param></param> /// <param></param> public void IsSuccess(T result = null, string message = "") { Message = message; Code = ServiceResultCode.Succeed; Result = result; } } }此时针对无需返回参数和需要返回参数的api都可以满足要求了。但是还有一种就没办法了,那就是带分页的数据,我们都应该知道想要分页,数据总数肯定是必不可少的。
所以此时还需要扩展一个分页的响应实体,当我们使用的时候,直接将分页响应实体作为上面写的ServiceResult<T>中的T参数,即可满足需求。
新建文件夹Paged,添加总数接口IHasTotalCount、返回结果列表接口IListResult
//IHasTotalCount.cs namespace Meowv.Blog.ToolKits.Base.Paged { public interface IHasTotalCount { /// <summary> /// 总数 /// </summary> int Total { get; set; } } } //IListResult.cs using System.Collections.Generic; namespace Meowv.Blog.ToolKits.Base.Paged { public interface IListResult<T> { /// <summary> /// 返回结果 /// </summary> IReadOnlyList<T> Item { get; set; } } }IListResult<T>接受一个参数,并将其指定为IReadOnlyList返回。