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

来源:https://www.cnblogs.com/tenghao510/archive/2019/11/25/11927930.html
-Advertisement-
Play Games

現階段,基本上都是前後端分離項目,這樣一來,就需要前後端配合,沒有統一返回格式,那麼對接起來會很麻煩,浪費時間。我們需要把所有介面及異常錯誤信息都返回一定的Json格式,有利於前端處理,從而提高了工作效率。 一、準備工作 定義響應實體類 /// <summary> /// 響應實體類 /// </s ...


現階段,基本上都是前後端分離項目,這樣一來,就需要前後端配合,沒有統一返回格式,那麼對接起來會很麻煩,浪費時間。我們需要把所有介面及異常錯誤信息都返回一定的Json格式,有利於前端處理,從而提高了工作效率。

一、準備工作

定義響應實體類

    /// <summary>
    /// 響應實體類
    /// </summary>
    public class ResultModel
    {
        /// <summary>
        /// 狀態碼
        /// </summary>
        public int ReturnCode { get; set; }

        /// <summary>
        /// 內容
        /// </summary>
        public object Data { get; set; }

        /// <summary>
        /// 錯誤信息
        /// </summary>
        public string ErrorMessage { get; set; }

        /// <summary>
        /// 是否成功
        /// </summary>
        public bool IsSuccess { get; set; }
    }

修改Controller層

在controller層處理業務請求,new 一個ResultModel 對象,返回給前端。

        /// <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 };
        }

這樣需要每個方法都需要重新new一個ResultModel 對象,感覺有點代碼冗餘。

我們只需要加幾個靜態方法,每個方法返回都是ResultModel對象,成功的時候調用ResultModel.OK,失敗的時候調用ResultModel.ERROR即可。

優化

添加兩個靜態方法

        /// <summary>
        /// 成功
        /// </summary>
        /// <param name="data">返回數據</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">錯誤信息</param>
        /// <param name="code">狀態碼</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);
        }

二、全局異常處理

通過全局異常處理,任何錯誤信息都會被攔截,返回統一格式。

定義全局異常處理中間件

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請求的函數。
        /// </summary>
        private readonly RequestDelegate _next;
        /// <summary>
        /// 構造函數
        /// </summary>
        /// <param name="next"></param>
        public ExceptionMiddleWare(RequestDelegate next)
        {
            _next = next;
        }

        public async Task Invoke(HttpContext context)
        {
            try
            {
                //拋給下一個中間件
                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已過期,請重新登錄.", code))).ConfigureAwait(false);
                        break;
                    default:
                        context.Response.ContentType = "application/json";
                        await context.Response.WriteAsync(JsonConvert.SerializeObject(ResultModel.Error("未知錯誤", code))).ConfigureAwait(false);
                        break;
                }
            }
        }
    }
}

註冊中間件

在Startup.cs啟動類的Configure方法中添加UseMiddleware方法

            //異常處理中間件
            app.UseMiddleware(typeof(ExceptionMiddleWare));

三、驗證實體模型

有兩種方式:

1.使用自定義過濾器

2.使用預設自帶的400模型驗證,需要在控制器上面加上【ApiController】,這種方式優先順序比較高,如果需要自定義模型驗證,則需要先關閉預設的模型驗證    

【ApiController】

自動推斷參數綁定:可以省略[FromBody]等參數特性

自動模型驗證:自動驗證模型是否合法

參考:https://blog.csdn.net/sD7O95O/article/details/81844154

            services.AddMvc(e =>
                {
                    e.Filters.Add<CheckModel>();
                })
                .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
                .ConfigureApiBehaviorOptions(e =>
                {
                    //關閉預設模型驗證
                    e.SuppressModelStateInvalidFilter = true;
                });

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

自定義過濾器

創建CheckModel過濾器繼承ActionFilterAttribute抽象類,重寫其中需要的方法

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using NetCoreWebApi.Util;

namespace NetCoreWebApi.Filter
{
    /// <summary>
    /// 驗證實體對象是否合法
    /// </summary>
    public class CheckModel : ActionFilterAttribute
    {
        /// <summary>
        /// Action 調用前執行
        /// </summary>
        /// <param name="actionContext"></param>
        public override void OnActionExecuting(ActionExecutingContext actionContext)
        {
            if (!actionContext.ModelState.IsValid)
            {
                //初始化返回結果
                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 BadRequestObjectResult(result);
            }
        }
        /// <summary>
        /// Action 方法調用後,Result 方法調用前執行
        /// </summary>
        /// <param name="context"></param>
        public override void OnActionExecuted(ActionExecutedContext context)
        {
} } }

將寫的過濾器註冊到全局

            services.AddMvc(e =>
                {
                    //註冊過濾器
                    e.Filters.Add<CheckModel>();
                })
                .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
                .ConfigureApiBehaviorOptions(e =>
                {
                    //關閉預設模型驗證
                    e.SuppressModelStateInvalidFilter = true;
                });

創建UserDto

using System.ComponentModel.DataAnnotations;

namespace NetCoreWebApi.Repository.Dto
{
    /// <summary>
    /// 用戶傳輸對象
    /// </summary>
    public class UserDto
    {
        /// <summary>
        /// 用戶Id
        /// </summary>
        [StringLength(32, ErrorMessage = "{0}最多{1}個字元"), Display(Name = "用戶Id")]
        public string UserId { get; set; }
        /// <summary>
        /// 用戶名
        /// </summary>
        [StringLength(20, ErrorMessage = "{0}最多{1}個字元"), Display(Name = "用戶名")]
        public string UserName { get; set; }
        /// <summary>
        /// 郵箱
        /// </summary>
        [StringLength(30, ErrorMessage = "{0}最多{1}個字元"), Display(Name = "郵箱")]
        public string Email { get; set; }
    }
}

測試

預設模型驗證

            services.AddMvc(e =>
                {
                    //註冊過濾器
                    //e.Filters.Add<CheckModel>();
                })
                .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
                .ConfigureApiBehaviorOptions(e =>
                {
                    ////關閉預設模型驗證
                    //e.SuppressModelStateInvalidFilter = true;
                    e.InvalidModelStateResponseFactory = actionContext =>
                    {
                        //獲取驗證失敗的模型欄位 
                        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 BadRequestObjectResult(ResultModel.Error(str, 400));
                    };
                });

兩種驗證方法效果是一致的


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前端開發工作中經常會碰到奇形怪狀的圖形,當然也少不了UI設計童鞋的腦洞和創意啦,初級的開發人員可能會選擇使用圖片做背景加上位置屬性實現,不過很多時候,CSS能實現的就不要再動用PS等工具了,時間寶貴,經驗更寶貴,畢竟簡單的搬磚很容易就會,不動“聲色“的實現才是來之不易的經(踩)驗(坑) 完事開通難, ...
  • 在看設計模式這本書,遇到一個令人疑惑的for迴圈語句 比較疑惑,因為從平時接觸的來看基本上都是 現在的疑惑如下 實際上上面的語句等同於,這是為什麼 原來這裡等同於把迴圈終止條件和迴圈被執行後執行的語句相結合了即把判斷和賦值放到一起了,一邊迴圈一邊賦值,i--是什麼判斷條件,當i--為fasle即,循 ...
  • 基於offsetHeight和clientHeight判斷是否出現滾動條 by:授客 QQ:1033553122 HTMLEelement.offsetHeight簡介 HTMLElement.offsetHeight 是一個只讀屬性,它返回該元素的像素高度,高度包含該元素的垂直內邊距和邊框,且是一 ...
  • 本次使用動態代理的初衷是學習Redis,使用Java操作Redis時用到Jedis的JedisPool,而後對Jedis的方法進一步封裝完善成為一個工具類。因為直接使用Jedis對象時,為了保證性能,總會需要手動的獲取到連接池中的連接,使用完成後還需要手動的釋放連接,都是完全重覆的操作。所以想要使用 ...
  • 程式員,真有必要瞭解架構嗎?有的人只關註眼下的“點”,有的人看到了延伸的“線”,還有人暢想出未來的“面”。就像在叢林中穿越,當你迷路找不到方向時,最好就是登上山頂或者爬上樹冠,讓自己有更寬廣的視野,從而找到通往目的地的最佳路徑。既要腳踏實地、低頭趕路,也要抬頭望天、暢想未來,正確的方向比速度更重要。 ...
  • 本文主要介紹了高德在服務單元化建設方面的一些實踐經驗,服務單元化建設面臨很多共性問題,如請求路由、單元封閉、數據同步,有的有成熟方案可以借鑒和使用,但不同公司的業務不盡相同,要儘可能的結合業務特點,做相應的設計和處理。 ...
  • 如果不知道 Jimu(積木) 是啥,請移步 ".Net Core 分散式微服務框架介紹 Jimu" 這次升級除了支持 .Net Core 3.0 還新增部分功能,如 REST, 鏈路跟蹤等,以下為詳細; 一、功能列表 | 功能 | 說明 |Jimu 1.0.0 | Jimu 0.6.0| | | | ...
  • 很多通用查詢器,對查詢條件中的AND及OR的支持度不是很好,要麼全部是AND要麼全部是OR。筆者通過一段時間的摸索,終於完成了一個自己較為滿意的通用查詢器, 可以實現多條件的AND及OR,現將實現過程記錄一下: 1、在App.config中添加資料庫連接字元串。 <connectionStrings ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...