日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

ASP.NET Core 2.2 WebApi 系列【八】統(tǒng)一返回格式(返回值、模型驗(yàn)證、異常)

 頭號(hào)碼甲 2020-05-05

現(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;
                });

參考:https://docs.microsoft.com/zh-cn/dotnet/api/microsoft.aspnetcore.mvc.apibehavioroptions?view=aspnetcore-2.2

自定義過(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)證方法效果是一致的

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多