系列文章
- 基于 abp vNext 和 .NET Core 開發博客專案 - 使用 abp cli 搭建專案
- 基于 abp vNext 和 .NET Core 開發博客專案 - 給專案瘦身,讓它跑起來
- 基于 abp vNext 和 .NET Core 開發博客專案 - 完善與美化,Swagger登場
- 基于 abp vNext 和 .NET Core 開發博客專案 - 資料訪問和代碼優先
- 基于 abp vNext 和 .NET Core 開發博客專案 - 自定義倉儲之增刪改查
- 基于 abp vNext 和 .NET Core 開發博客專案 - 統一規范API,包裝回傳模型
- 基于 abp vNext 和 .NET Core 開發博客專案 - 再說Swagger,分組、描述、小綠鎖
- 基于 abp vNext 和 .NET Core 開發博客專案 - 接入GitHub,用JWT保護你的API
- 基于 abp vNext 和 .NET Core 開發博客專案 - 例外處理和日志記錄
- 基于 abp vNext 和 .NET Core 開發博客專案 - 使用Redis快取資料
- 基于 abp vNext 和 .NET Core 開發博客專案 - 集成Hangfire實作定時任務處理
- 基于 abp vNext 和 .NET Core 開發博客專案 - 用AutoMapper搞定物件映射
- 基于 abp vNext 和 .NET Core 開發博客專案 - 定時任務最佳實戰(一)
- 基于 abp vNext 和 .NET Core 開發博客專案 - 定時任務最佳實戰(二)
- 基于 abp vNext 和 .NET Core 開發博客專案 - 定時任務最佳實戰(三)
- 基于 abp vNext 和 .NET Core 開發博客專案 - 博客介面實戰篇(一)
- 基于 abp vNext 和 .NET Core 開發博客專案 - 博客介面實戰篇(二)
- 基于 abp vNext 和 .NET Core 開發博客專案 - 博客介面實戰篇(三)
- 基于 abp vNext 和 .NET Core 開發博客專案 - 博客介面實戰篇(四)
- 基于 abp vNext 和 .NET Core 開發博客專案 - 博客介面實戰篇(五)
- 基于 abp vNext 和 .NET Core 開發博客專案 - Blazor 實戰系列(一)
- 基于 abp vNext 和 .NET Core 開發博客專案 - Blazor 實戰系列(二)
- 基于 abp vNext 和 .NET Core 開發博客專案 - Blazor 實戰系列(三)
- 基于 abp vNext 和 .NET Core 開發博客專案 - Blazor 實戰系列(四)
- 基于 abp vNext 和 .NET Core 開發博客專案 - Blazor 實戰系列(五)
- 基于 abp vNext 和 .NET Core 開發博客專案 - Blazor 實戰系列(六)
- 基于 abp vNext 和 .NET Core 開發博客專案 - Blazor 實戰系列(七)
- 基于 abp vNext 和 .NET Core 開發博客專案 - Blazor 實戰系列(八)
- 基于 abp vNext 和 .NET Core 開發博客專案 - Blazor 實戰系列(九)
- 基于 abp vNext 和 .NET Core 開發博客專案 - 終結篇之發布專案
上一篇文章(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; } = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
/// <summary>
/// 回應成功
/// </summary>
/// <param name="message"></param>
/// <param name="data"></param>
/// <returns></returns>
public void IsSuccess(string message = "")
{
Message = message;
Code = ServiceResultCode.Succeed;
}
/// <summary>
/// 回應失敗
/// </summary>
/// <param name="message"></param>
/// <param name="data"></param>
/// <returns></returns>
public void IsFailed(string message = "")
{
Message = message;
Code = ServiceResultCode.Failed;
}
/// <summary>
/// 回應失敗
/// </summary>
/// <param name="exexception></param>
/// <param name="data"></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 name="T"></typeparam>
public class ServiceResult<T> : ServiceResult where T : class
{
/// <summary>
/// 回傳結果
/// </summary>
public T Result { get; set; }
/// <summary>
/// 回應成功
/// </summary>
/// <param name="result"></param>
/// <param name="message"></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回傳,
現在來實作IListResult介面,新建ListResult實作類,繼承IListResult,在建構式中為其賦值,代碼如下:
//ListResult.cs
using System.Collections.Generic;
namespace Meowv.Blog.ToolKits.Base.Paged
{
public class ListResult<T> : IListResult<T>
{
IReadOnlyList<T> item;
public IReadOnlyList<T> Item
{
get => item ?? (item = new List<T>());
set => item = value;
}
public ListResult()
{
}
public ListResult(IReadOnlyList<T> item)
{
Item = item;
}
}
}
最后新建我們的分頁回應物體介面:IPagedList和分頁回應物體實作類:PagedList,它同時也要接受一個泛型引數 T,
介面繼承了IListResult<T>和IHasTotalCount,實作類繼承ListResult<T>和IPagedList<T>,在建構式中為其賦值,代碼如下:
//IPagedList.cs
namespace Meowv.Blog.ToolKits.Base.Paged
{
public interface IPagedList<T> : IListResult<T>, IHasTotalCount
{
}
}
//PagedList.cs
using Meowv.Blog.ToolKits.Base.Paged;
using System.Collections.Generic;
namespace Meowv.Blog.ToolKits.Base
{
/// <summary>
/// 分頁回應物體
/// </summary>
/// <typeparam name="T"></typeparam>
public class PagedList<T> : ListResult<T>, IPagedList<T>
{
/// <summary>
/// 總數
/// </summary>
public int Total { get; set; }
public PagedList()
{
}
public PagedList(int total, IReadOnlyList<T> result) : base(result)
{
Total = total;
}
}
}
到這里我們的回傳模型就圓滿了,看一下此時下我們的專案層級目錄,

接下來去實踐一下,修改我們之前創建的增刪改查介面的回傳引數,
//IBlogService.cs
using Meowv.Blog.Application.Contracts.Blog;
using Meowv.Blog.ToolKits.Base;
using System.Threading.Tasks;
namespace Meowv.Blog.Application.Blog
{
public interface IBlogService
{
//Task<bool> InsertPostAsync(PostDto dto);
Task<ServiceResult<string>> InsertPostAsync(PostDto dto);
//Task<bool> DeletePostAsync(int id);
Task<ServiceResult> DeletePostAsync(int id);
//Task<bool> UpdatePostAsync(int id, PostDto dto);
Task<ServiceResult<string>> UpdatePostAsync(int id, PostDto dto);
//Task<PostDto> GetPostAsync(int id);
Task<ServiceResult<PostDto>> GetPostAsync(int id);
}
}
介面全部為異步方式,用ServiceResult包裹作為回傳模型,添加和更新T引數為string型別,洗掉就直接不回傳結果,然后查詢為:ServiceResult<PostDto>,再看一下實作類:
//BlogService.cs
...
public async Task<ServiceResult<string>> InsertPostAsync(PostDto dto)
{
var result = new ServiceResult<string>();
var entity = new Post
{
Title = dto.Title,
Author = dto.Author,
Url = dto.Url,
Html = dto.Html,
Markdown = dto.Markdown,
CategoryId = dto.CategoryId,
CreationTime = dto.CreationTime
};
var post = await _postRepository.InsertAsync(entity);
if (post == null)
{
result.IsFailed("添加失敗");
return result;
}
result.IsSuccess("添加成功");
return result;
}
public async Task<ServiceResult> DeletePostAsync(int id)
{
var result = new ServiceResult();
await _postRepository.DeleteAsync(id);
return result;
}
public async Task<ServiceResult<string>> UpdatePostAsync(int id, PostDto dto)
{
var result = new ServiceResult<string>();
var post = await _postRepository.GetAsync(id);
if (post == null)
{
result.IsFailed("文章不存在");
return result;
}
post.Title = dto.Title;
post.Author = dto.Author;
post.Url = dto.Url;
post.Html = dto.Html;
post.Markdown = dto.Markdown;
post.CategoryId = dto.CategoryId;
post.CreationTime = dto.CreationTime;
await _postRepository.UpdateAsync(post);
result.IsSuccess("更新成功");
return result;
}
public async Task<ServiceResult<PostDto>> GetPostAsync(int id)
{
var result = new ServiceResult<PostDto>();
var post = await _postRepository.GetAsync(id);
if (post == null)
{
result.IsFailed("文章不存在");
return result;
}
var dto = new PostDto
{
Title = post.Title,
Author = post.Author,
Url = post.Url,
Html = post.Html,
Markdown = post.Markdown,
CategoryId = post.CategoryId,
CreationTime = post.CreationTime
};
result.IsSuccess(dto);
return result;
}
...
當成功時,呼叫IsSuccess(...)方法,當失敗時,呼叫IsFailed(...)方法,最終我們回傳的是new ServiceResult()或者new ServiceResult<T>()物件,
同時不要忘記在Controller中也需要修改一下,如下:
//BlogController.cs
...
...
public async Task<ServiceResult<string>> InsertPostAsync([FromBody] PostDto dto)
...
...
public async Task<ServiceResult> DeletePostAsync([Required] int id)
...
...
public async Task<ServiceResult<string>> UpdatePostAsync([Required] int id, [FromBody] PostDto dto)
...
...
public async Task<ServiceResult<PostDto>> GetPostAsync([Required] int id)
...
...
此時再去我們的Swagger檔案發起請求,這里我們呼叫一下查詢介面看看回傳的樣子,看看效果吧,

本篇內容比較簡單,主要是包裝我們的api,讓回傳結果顯得比較正式一點,那么,你學會了嗎???????
開源地址:https://github.com/Meowv/Blog/tree/blog_tutorial
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/27052.html
標籤:.NET Core
