現(xiàn)階段,基本上都是前后端分離項(xiàng)目,這樣一來(lái),就需要前后端配合,沒(méi)有統(tǒng)一返回格式,那么對(duì)接起來(lái)會(huì)很麻煩,浪費(fèi)時(shí)間。我們需要把所有接口及異常錯(cuò)誤信息都返回一定的Json格式,有利于前端處理,從而提高了工作效率。 一、準(zhǔn)備工作定義響應(yīng)實(shí)體類/// <summary> /// 響應(yīng)實(shí)體類 /// </summary> public class ResultModel { /// <summary> /// 狀態(tài)碼 /// </summary> public int ReturnCode { get; set; } /// <summary> /// 內(nèi)容 /// </summary> public object Data { get; set; } /// <summary> /// 錯(cuò)誤信息 /// </summary> public string ErrorMessage { get; set; } /// <summary> /// 是否成功 /// </summary> public bool IsSuccess { get; set; } } 修改Controller層在controller層處理業(yè)務(wù)請(qǐng)求,new 一個(gè)ResultModel 對(duì)象,返回給前端。 /// <summary> /// 查詢用戶 /// </summary> /// <returns></returns> [Route("getUser")] [HttpGet] public ResultModel GetUser() { var data = _userRepository.GetAll().ToList(); return new ResultModel() { Data = data, ErrorMessage = null, IsSuccess = true, ReturnCode = 200 }; } 這樣需要每個(gè)方法都需要重新new一個(gè)ResultModel 對(duì)象,感覺(jué)有點(diǎn)代碼冗余。 我們只需要加幾個(gè)靜態(tài)方法,每個(gè)方法返回都是ResultModel對(duì)象,成功的時(shí)候調(diào)用ResultModel.OK,失敗的時(shí)候調(diào)用ResultModel.ERROR即可。 優(yōu)化添加兩個(gè)靜態(tài)方法 /// <summary> /// 成功 /// </summary> /// <param name="data">返回?cái)?shù)據(jù)</param> /// <returns></returns> public static ResultModel Ok(object data) { return new ResultModel { Data = data, ErrorMessage = null, IsSuccess = true, ReturnCode = 200 }; } /// <summary> /// 失敗 /// </summary> /// <param name="str">錯(cuò)誤信息</param> /// <param name="code">狀態(tài)碼</param> /// <returns></returns> public static ResultModel Error(string str,int code) { return new ResultModel { Data = null, ErrorMessage = str, IsSuccess = false, ReturnCode = code }; } 修改控制器 /// <summary> /// 查詢用戶 /// </summary> /// <returns></returns> [Route("getUser")] [HttpGet] public ResultModel GetUser() { var data = _userRepository.GetAll().ToList(); return ResultModel.Ok(data); } 二、全局異常處理通過(guò)全局異常處理,任何錯(cuò)誤信息都會(huì)被攔截,返回統(tǒng)一格式。 定義全局異常處理中間件using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using NetCoreWebApi.Util; using Newtonsoft.Json; namespace NetCoreWebApi.Filter { /// <summary> /// 處理全局信息中間件 /// </summary> public class ExceptionMiddleWare { /// <summary> /// 處理HTTP請(qǐng)求的函數(shù)。 /// </summary> private readonly RequestDelegate _next; /// <summary> /// 構(gòu)造函數(shù) /// </summary> /// <param name="next"></param> public ExceptionMiddleWare(RequestDelegate next) { _next = next; } public async Task Invoke(HttpContext context) { try { //拋給下一個(gè)中間件 await _next(context); } catch (Exception ex) { await WriteExceptionAsync(context, ex); } finally { await WriteExceptionAsync(context, null); } } private async Task WriteExceptionAsync(HttpContext context, Exception exception) { if (exception != null) { var response = context.Response; var message = exception.InnerException == null ? exception.Message : exception.InnerException.Message; response.ContentType = "application/json"; await response.WriteAsync(JsonConvert.SerializeObject(ResultModel.Error(message, 400))).ConfigureAwait(false); } else { var code = context.Response.StatusCode; switch (code) { case 200: return; case 204: return; case 401: context.Response.ContentType = "application/json"; await context.Response.WriteAsync(JsonConvert.SerializeObject(ResultModel.Error("token已過(guò)期,請(qǐng)重新登錄.", code))).ConfigureAwait(false); break; default: context.Response.ContentType = "application/json"; await context.Response.WriteAsync(JsonConvert.SerializeObject(ResultModel.Error("未知錯(cuò)誤", code))).ConfigureAwait(false); break; } } } } } 注冊(cè)中間件在Startup.cs啟動(dòng)類的Configure方法中添加UseMiddleware方法 //異常處理中間件 app.UseMiddleware(typeof(ExceptionMiddleWare)); 三、驗(yàn)證實(shí)體模型有兩種方式: 1.使用自定義過(guò)濾器 2.使用默認(rèn)自帶的400模型驗(yàn)證,需要在控制器上面加上【ApiController】,這種方式優(yōu)先級(jí)比較高,如果需要自定義模型驗(yàn)證,則需要先關(guān)閉默認(rèn)的模型驗(yàn)證 【ApiController】 自動(dòng)推斷參數(shù)綁定:可以省略[FromBody]等參數(shù)特性 自動(dòng)模型驗(yàn)證:自動(dòng)驗(yàn)證模型是否合法 參考:https://blog.csdn.net/sD7O95O/article/details/81844154 services.AddMvc(e => { e.Filters.Add<CheckModel>(); }) .SetCompatibilityVersion(CompatibilityVersion.Version_2_2) .ConfigureApiBehaviorOptions(e => { //關(guān)閉默認(rèn)模型驗(yàn)證 e.SuppressModelStateInvalidFilter = true; }); 自定義過(guò)濾器創(chuàng)建CheckModel過(guò)濾器繼承ActionFilterAttribute抽象類,重寫(xiě)其中需要的方法 using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using NetCoreWebApi.Util; namespace NetCoreWebApi.Filter { /// <summary> /// 驗(yàn)證實(shí)體對(duì)象是否合法 /// </summary> public class CheckModel : ActionFilterAttribute { /// <summary> /// Action 調(diào)用前執(zhí)行 /// </summary> /// <param name="actionContext"></param> public override void OnActionExecuting(ActionExecutingContext actionContext) { if (!actionContext.ModelState.IsValid) { //初始化返回結(jié)果 var result = new ResultModel { IsSuccess = false, ReturnCode = 400 }; foreach (var item in actionContext.ModelState.Values) { foreach (var error in item.Errors) { result.ErrorMessage += error.ErrorMessage + "|"; } } actionContext.Result = new JsonResult(result); } } /// <summary> /// Action 方法調(diào)用后,Result 方法調(diào)用前執(zhí)行 /// </summary> /// <param name="context"></param> public override void OnActionExecuted(ActionExecutedContext context) { 將寫(xiě)的過(guò)濾器注冊(cè)到全局 services.AddMvc(e => { //注冊(cè)過(guò)濾器 e.Filters.Add<CheckModel>(); }) .SetCompatibilityVersion(CompatibilityVersion.Version_2_2) .ConfigureApiBehaviorOptions(e => { //關(guān)閉默認(rèn)模型驗(yàn)證 e.SuppressModelStateInvalidFilter = true; }); 創(chuàng)建UserDto using System.ComponentModel.DataAnnotations; namespace NetCoreWebApi.Repository.Dto { /// <summary> /// 用戶傳輸對(duì)象 /// </summary> public class UserDto { /// <summary> /// 用戶Id /// </summary> [StringLength(32, ErrorMessage = "{0}最多{1}個(gè)字符"), Display(Name = "用戶Id")] public string UserId { get; set; } /// <summary> /// 用戶名 /// </summary> [StringLength(20, ErrorMessage = "{0}最多{1}個(gè)字符"), Display(Name = "用戶名")] public string UserName { get; set; } /// <summary> /// 郵箱 /// </summary> [StringLength(30, ErrorMessage = "{0}最多{1}個(gè)字符"), Display(Name = "郵箱")] public string Email { get; set; } } } 測(cè)試 默認(rèn)模型驗(yàn)證services.AddMvc(e => { //注冊(cè)過(guò)濾器 //e.Filters.Add<CheckModel>(); }) .SetCompatibilityVersion(CompatibilityVersion.Version_2_2) .ConfigureApiBehaviorOptions(e => { ////關(guān)閉默認(rèn)模型驗(yàn)證 //e.SuppressModelStateInvalidFilter = true; e.InvalidModelStateResponseFactory = actionContext => { //獲取驗(yàn)證失敗的模型字段 var errors = actionContext.ModelState .Where(e1 => e1.Value.Errors.Count > 0) .Select(e1 => e1.Value.Errors.First().ErrorMessage) .ToList(); var str = string.Join("|", errors); return new JsonResult(ResultModel.Error(str, 400)); }; }); 兩種驗(yàn)證方法效果是一致的 |
|