.net core 数据统一响应分享

原文:.net core 数据统一响应分享

前言

代码胡乱写,维护火葬场!

在平时工作中遇到前同事写接口这样返回值
.net core 数据统一响应分享
.net core 数据统一响应分享
当接口返回1时,不去看他的代码就永远猜不到这个1代表的是返回成功还是返回值

稍微好点的
.net core 数据统一响应分享
维护和改bug简直让人疯狂,导致大部分时间浪费在“体会”别人返回值的逻辑中

天天加班与救bug于水火之中
.net core 数据统一响应分享

合理分配前后端返回值很重要!

一般我们常用统一的格式返回json,无论后台是运行正常还是发生异常,响应给前端的数据格式是不变的!

    public class Result<T> where T : class
    {
        public ResultCode code { get; set; }

        public string msg { get; set; }

        public T data { get; set; }
    }

.net core 数据统一响应分享

包装一下,通常使用构造函数

    public class Result<T> where T : class
    {
        public ResultCode code { get; set; }

        public string msg { get; set; }

        public T data { get; set; }

        public Result(T data)
        {
            code = ResultCode.Ok;
            msg = ResultCode.Ok.GetDescription();
            this.data = data;
        }

        public Result(ResultCode code, string msg, T data)
        {
            this.code = code;
            this.msg = msg ?? code.GetDescription();
            this.data = data;
        }
    }

这么使用new Result<Store>(code, msg, data)使用起来还是不够简化
继续封装

    public class Result<T> where T : class
    {
        public ResultCode code { get; set; }

        public string msg { get; set; }

        public T data { get; set; }

        public Result(T data)
        {
            code = ResultCode.Ok;
            msg = ResultCode.Ok.GetDescription();
            this.data = data;
        }

        public Result(ResultCode code, string msg, T data)
        {
            this.code = code;
            this.msg = msg ?? code.GetDescription();
            this.data = data;
        }

        public static Result<T> FromCode(ResultCode code, string msg = null, T data = default)
        {
            if (data == null)
                data = (T) new Object();
            return new Result<T>(code, msg, data);
        }

        public static Result<T> Ok(T data)
        {
            return new Result<T>(data);
        }

        public static Result<T> FromError(ResultCode code = ResultCode.Fail, string msg = null, T data = default)
        {
            return new Result<T>(code, msg, data);
        }
    }
        [HttpGet]
        public Result<Store> Get()
        {
            return Result<Store>.Ok(new Store());
        }

这样就稍微好点了

全局处理响应数据

虽然控制器返回值可以统一了,但是异常处理并没有统一,这时候就需要建个中间件/异常过滤器进行处理异常

    app.UseMiddleware<GlobalExceptionHandlerMiddleware>();
    public class GlobalExceptionHandlerMiddleware
    {
        private readonly RequestDelegate _next;

        public GlobalExceptionHandlerMiddleware(RequestDelegate next)
        {
            _next = next;
        }

        public async Task Invoke(HttpContext context)
        {
            try
            {
                await _next(context);
            }
            catch (System.Exception ex)
            {
                context.Response.StatusCode = 500;
                context.Response.ContentType = "text/json;charset=utf-8;";

                if (ex is ResultException == false)
                {
                    var logger = context.RequestServices.GetRequiredService<ILoggerFactory>().CreateLogger<GlobalExceptionHandlerMiddleware>();
                    logger.LogError(1, ex, ex.Message);
                }

                var json = Result<object>.FromCode(ResultCode.Fail, ex.Message);
                var error = JsonSerializer.Serialize(json);

                await context.Response.WriteAsync(error);
            }
        }
    }

有些异常是不需要记录的,这时候可以自定义ResultException进行判断

    public class ResultException : Exception
    {
        public ResultException(string message) : base(message)
        {
        }

        public ResultException(string message, Exception e) : base(message, e)
        {

        }
    }

                if (ex is ResultException == false)
                {
                    var logger = context.RequestServices.GetRequiredService<ILoggerFactory>().CreateLogger<GlobalExceptionHandlerMiddleware>();
                    logger.LogError(1, ex, ex.Message);
                }

参数校验处理

一个接口一般对参数(请求数据)都会进行安全校验,按照之前的格式返回验证异常。

    public class ModelActionFilter : ActionFilterAttribute, IActionFilter
    {
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            if (!context.ModelState.IsValid)
            {
                var errorResults = new List<ErrorResultDto>();
                foreach (var item in context.ModelState)
                {
                    var result = new ErrorResultDto
                    {
                        Field = item.Key,
                        Msg = "",
                    };
                    foreach (var error in item.Value.Errors)
                    {
                        if (!string.IsNullOrEmpty(result.Msg))
                        {
                            result.Msg += ‘|‘;
                        }
                        result.Msg += error.ErrorMessage;
                    }
                    errorResults.Add(result);
                }
                context.Result = new JsonResult(Result<List<ErrorResultDto>>.FromCode(ResultCode.InvalidData, data: errorResults));
            }
        }
    }

    public class ErrorResultDto
    {
        /// <summary>
        /// 参数领域
        /// </summary>
        public string Field { get; set; }

        /// <summary>
        /// 错误信息
        /// </summary>
        public string Msg { get; set; }
    }

Startup.cs

            services.AddControllers(options =>
            {
                options.Filters.Add(new ModelActionFilter());
                options.MaxModelValidationErrors = 50;
                options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor(
                    _ => "该字段不可为空。");
            })

.net core 数据统一响应分享

上一篇:将JSON字符串反序列化为指定的.NET对象类型


下一篇:HTML