打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
ASP.NET Core 2.2 WebApi 系列【八】统一返回格式(返回值、模型验证、异常)

现阶段,基本上都是前后端分离项目,这样一来,就需要前后端配合,没有统一返回格式,那么对接起来会很麻烦,浪费时间。我们需要把所有接口及异常错误信息都返回一定的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 JsonResult(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 JsonResult(ResultModel.Error(str, 400));                    };                });

两种验证方法效果是一致的

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Web API 下的 ActionFilter 与 ExceptionFilter
网站安全通用防护代码(C#版本源码提供)
SignalR循序渐进(三)简易的集群通讯组件
用Redis实现Session功能,实现单点登录
WPF 组件间通信 MVVM 进行解耦
微信小程序支付简单小结与梳理
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服