.NET core 自定义过滤器 Filter 实现webapi RestFul 统一接口数据返回格式

news/2024/5/19 21:44:55 标签: .netcore, 过滤器, RestFul, webapi, 中间件

之前写过使用自定义返回类的方式来统一接口数据返回格式,.Net Core webapi RestFul 统一接口数据返回格式-CSDN博客

但是这存在一个问题,不是所有接口会按照定义的数据格式返回,除非每个接口都返回我们自定义的类,这种实现起来不太现实。

类似这样,定义一个接口:

返回的只是只有user的json对象:

这显然不是我们想要的结果,我们想要的结果是这样:

{
  "statusCode": 200,
  "successful": true,
  "message": null,
  "data": {
    "userId": "001",
    "userName": "小王",
    "password": "123"
  }
}

我们需要不管接口定义的返回类型是什么,最后的结果都是统一的数据格式,需要实现这个功能就需要自定义一个过滤器来实现。

具体实现代码如下:

自定义一个过滤器类 ResponseWrapperFilter.cs

public class ResponseWrapperFilter : IAsyncResultFilter
    {
        public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
        {
            if (context.Result is ObjectResult objectResult)
            {
                if (objectResult.Value is IApiResponse apiResponse)
                {
                    objectResult.StatusCode = apiResponse.StatusCode;
                    context.HttpContext.Response.StatusCode = apiResponse.StatusCode;
                }
                else
                {
                    var statusCode = objectResult.StatusCode ?? context.HttpContext.Response.StatusCode;

                    var wrapperResp = new ApiResponse<object>
                    {
                        StatusCode = statusCode,
                        Successful = statusCode is >= 200 and < 400,
                        Data = objectResult.Value,
                    };

                    objectResult.Value = wrapperResp;
                    objectResult.DeclaredType = wrapperResp.GetType();
                }
            }

            await next();
        }
    }

在代码中进行判断,当响应的类型是 ObjectResult 时,把这个响应结果拿出来,再判断是不是 IApiResponse 类型。

前面我们介绍过,所有 ApiResponse 都实现了 IApiResponse 这个接口,所以可以判断是不是 IApiResponse 类型来确定这个返回结果是否包装过。

没包装的话就给包装一下,就这么简单。

附上 ApiResponse.cs  IApiResponse.cs 代码

    public interface IApiResponse
    {
        public int StatusCode { get; set; }
        public bool Successful { get; set; }
        public string? Message { get; set; }
    }

    public interface IApiResponse<T> : IApiResponse
    {
        public T? Data { get; set; }
    }

    public interface IApiErrorResponse
    {
        public Dictionary<string, object> ErrorData { get; set; }
    }


    public class ApiResponse<T> : IApiResponse<T>
    {
        public ApiResponse()
        {
        }

        public ApiResponse(T? data)
        {
            Data = data;
        }

        public int StatusCode { get; set; } = 200;
        public bool Successful { get; set; } = true;
        public string? Message { get; set; }

        public T? Data { get; set; }

        /// <summary>
        /// 实现将 <see cref="ApiResponse"/> 隐式转换为 <see cref="ApiResponse{T}"/>
        /// </summary>
        /// <param name="apiResponse"><see cref="ApiResponse"/></param>
        public static implicit operator ApiResponse<T>(ApiResponse apiResponse)
        {
            return new ApiResponse<T>
            {
                StatusCode = apiResponse.StatusCode,
                Successful = apiResponse.Successful,
                Message = apiResponse.Message
            };
        }
    }


    public class ApiResponse : IApiResponse, IApiErrorResponse
    {
        public int StatusCode { get; set; } = 200;
        public bool Successful { get; set; } = true;
        public string? Message { get; set; }
        public object? Data { get; set; }

        /// <summary>
        /// 可序列化的错误
        /// <para>用于保存模型验证失败的错误信息</para>
        /// </summary>
        public Dictionary<string, object>? ErrorData { get; set; }

        public ApiResponse()
        {
        }

        public ApiResponse(object data)
        {
            Data = data;
        }

        public static ApiResponse NoContent(string message = "NoContent")
        {
            return new ApiResponse
            {
                StatusCode = StatusCodes.Status204NoContent,
                Successful = true,
                Message = message
            };
        }

        public static ApiResponse Ok(string message = "Ok")
        {
            return new ApiResponse
            {
                StatusCode = StatusCodes.Status200OK,
                Successful = true,
                Message = message
            };
        }

        public static ApiResponse Ok(object data, string message = "Ok")
        {
            return new ApiResponse
            {
                StatusCode = StatusCodes.Status200OK,
                Successful = true,
                Message = message,
                Data = data
            };
        }

        public static ApiResponse Unauthorized(string message = "Unauthorized")
        {
            return new ApiResponse
            {
                StatusCode = StatusCodes.Status401Unauthorized,
                Successful = false,
                Message = message
            };
        }

        public static ApiResponse NotFound(string message = "NotFound")
        {
            return new ApiResponse
            {
                StatusCode = StatusCodes.Status404NotFound,
                Successful = false,
                Message = message
            };
        }

        public static ApiResponse BadRequest(string message = "BadRequest")
        {
            return new ApiResponse
            {
                StatusCode = StatusCodes.Status400BadRequest,
                Successful = false,
                Message = message
            };
        }

        public static ApiResponse BadRequest(ModelStateDictionary modelState, string message = "ModelState is not valid.")
        {
            return new ApiResponse
            {
                StatusCode = StatusCodes.Status400BadRequest,
                Successful = false,
                Message = message,
                ErrorData = new SerializableError(modelState)
            };
        }

        public static ApiResponse Error(string message = "Error", Exception? exception = null)
        {
            object? data = null;
            if (exception != null)
            {
                data = new
                {
                    exception.Message,
                    exception.Data
                };
            }

            return new ApiResponse
            {
                StatusCode = StatusCodes.Status500InternalServerError,
                Successful = false,
                Message = message,
                Data = data
            };
        }
    }

之后在 Program.cs 里注册一下这个过滤器

services.AddControllers(options =>
{
    options.Filters.Add<ResponseWrapperFilter>();
});

再次调用GetUser接口,可以看到已经包装成统一的数据格式返回了:

而对于之前已经定义返回类型是ApiResponse的接口也不会重复包装:


http://www.niftyadmin.cn/n/5278798.html

相关文章

深入理解 Spring Boot:核心知识与约定大于配置原则

深入理解 Spring Boot&#xff1a;核心知识与约定大于配置原则 简单说一下为什么要有 Spring Boot&#xff1f; 因为 Spring 的缺点。 虽然 Spring 的组件代码是轻量级的&#xff0c;但它的配置却是重量级的(需要大量 XML 配置) 为了减少配置文件&#xff0c;简化开发 Spri…

喜报频传 小匠物联荣获2023物联网应用示范项目奖

12月21日&#xff0c;新一届物联网产业与智慧城市发展年会在北京京都信苑饭店隆重举行。会上&#xff0c;喜报再传&#xff0c;小匠物联凭借自创的小匠产测系统申报了“2023年物联网与智慧城市创新应用项目方案”&#xff0c;并最终荣获“2023物联网应用示范项目奖”&#xff0…

如何添加jar包到本地Maven项目中

在 Maven 中添加一个外部 JAR 包的依赖&#xff0c;你需要使用 Maven 的 <dependency> 元素来指定该 JAR 包的坐标信息。以下是具体的步骤&#xff1a; 将 JAR 包手动添加到 Maven 本地仓库&#xff1a; 首先&#xff0c;确保将外部 JAR 包手动添加到 Maven 本地仓库。可…

服务器数据恢复-服务器断电导致linux操作系统数据丢失的数据恢复案例

linux操作系统服务器数据恢复环境&#xff1a; 某品牌R730服务器MD3200系列存储&#xff0c;linux操作系统。 服务器故障&#xff1a; 机房意外断电导致服务器linux操作系统部分文件丢失。 服务器数据恢复过程&#xff1a; 1、将故障服务器连接到北亚企安数据恢复中心备份服务器…

C#文件操作(二)

一、前言 文章的续作前文是&#xff1a; C#文件操作&#xff08;一&#xff09;-CSDN博客https://blog.csdn.net/qq_71897293/article/details/135117922?spm1001.2014.3001.5501 二、流 流是序列化设备的抽象表示序列化设备可以线性方式储存数据并可按照同样的方式访问一次…

产品原型设计软件 Axure RP 9 mac支持多人写作设计

axure rp 9 mac是一款产品原型设计软件&#xff0c;它可以让你在上面任意构建草图、框线图、流程图以及产品模型&#xff0c;还能够注释一些重要地方&#xff0c;axure rp汉化版可支持同时多人写作设计和版本管理控制&#xff0c;这款交互式原型设计工具可以帮助设计者制作出高…

【JVM基础】 JVM 如何加载一个类以及类加载机制

文章目录 1、什么时候一个类会被加载&#xff1f;1、包含 main 方法的主类2、非 包含 main 方法的主类&#xff0c;什么时候去加载&#xff1f; 3、类加载器如何加载一个类&#xff1f;1、验证阶段&#xff1a;2、准备阶段&#xff1a;3、解析阶段&#xff1a;4、初始化&#x…

解决win10下强制设置web浏览器为microsoft edge的方法

目录 问题场景实现方法禁止edge默认选项设置默认浏览器 反思 问题场景 因为一些特殊的原因&#xff0c;我需要第二个浏览器&#xff0c;我的第一个浏览器是google的chrome浏览器&#xff0c;所以我选择的是windows的默认浏览器&#xff0c;就是microsoft edge浏览器&#xff0…