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

之前写过使用自定义返回类的方式来统一接口数据返回格式,.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.mfbz.cn/a/263031.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

集群与分布式的概念及区别

目前在工作中经常接触到集群的概念&#xff0c;通过这篇文章总结一下集群的几种方式以及和分布式对比学习 1.集群&#xff08;Cluster&#xff09; 集群是由多个计算机节点组成的网络&#xff0c;旨在共同提供服务&#xff0c;并确保高性能和高可用性。在高可用集群中&#xf…

CH06_访问数据结构

Visitor 模式 访问者模式&#xff08;Visitor&#xff09;&#xff0c;表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的提前下定义作用于这些元素的新操作。 类图 说明 Visitor&#xff08;访问者&#xff09; Visitor角色负责对数据结构中每一个…

Java_集合进阶Map集合

一、Map集合 1.1 Map概述体系 各位同学&#xff0c;前面我们已经把单列集合学习完了&#xff0c;接下来我们要学习的是双列集合。首先我们还是先认识一下什么是双列集合。 所谓双列集合&#xff0c;就是说集合中的元素是一对一对的。Map集合中的每一个元素是以keyvalue的形式…

Sublime Text 3配置 C# 开发环境

Sublime Text 3配置 C# 开发环境 一、引言二、主要内容1. 初识 Sublime Text 32. 初识 C#3. 接入 .NET Framework3.1 下载 .NET Framework3.2 环境变量配置 4. 配置 C# 开发环境5. 编写 C# 代码6. 运行 C# 代码 三、总结 一、引言 C# 是一种面向对象的编程语言&#xff0c;由微…

php学习02-php标记风格

<?php echo "这是xml格式风格" ?><script language"php">echo 脚本风格标记 </script><% echo "这是asp格式风格" %>推荐使用xml格式风格 如果要使用简短风格和ASP风格&#xff0c;需要在php.ini中对其进行配置&#…

在做题中学习(38):快乐数

202. 快乐数 - 力扣&#xff08;LeetCode&#xff09; 理解&#xff1a;根据定义一共有两种情况 1.最后变为1 2.最后变为环 思路&#xff1a;可以把两个情况都认为有环&#xff0c;第一个是环一直为1 &#xff08;快满指针法&#xff09; 定义一个快指针和慢指针&#xff0c…

前端---后端 跨域?

一、跨域 &#xff1f; 跨域&#xff08;Cross-Origin Resource Sharing&#xff0c;CORS&#xff09;是浏览器的一项安全功能&#xff0c;它用于限制一个域名下的文档如何从另一个不同的域名、端口或协议请求资源。跨域资源共享&#xff08;Cross-Origin Resource Sharing&am…

黑马点评09 秒杀功能总结

1.整体业务流程 1.1 redis判断流程 &#xff08;单线程&#xff09; 1.首先获取订单id和用户id&#xff0c;调用lua脚本进行redis操作&#xff0c;lua内包括 对购买资格/库存充足的判断 、 扣库存下单、发送订单消息到Stream。 2.Stream组成消息队列&#xff0c;有异常自动放到…

【数字图像处理】实验一 图像基本运算

图像基本运算 一、实验内容&#xff1a; 1&#xff0e; 熟悉和掌握利用Matlab工具进行数字图像的读、写、显示等数字图像处理基本步骤。 2&#xff0e; 熟练掌握各种图像点运算的基本原理及方法。 3&#xff0e; 能够从深刻理解点运算&#xff0c;并能够思考拓展到一定的应用领…

项目中webpack优化配置(1)

项目中webpack优化配置 一. 开发效率&#xff0c; 体验 1. DLL&#xff08;开发过程中减少构建时间和增加应用程序的性能&#xff09; 使用 DllPlugin 进行分包&#xff0c;使用 DllReferencePlugin(索引链接) 对 manifest.json 引用&#xff0c;让一些基本不会改动的代码先…

展馆漫游可视化与智慧展厅:开启未来展览新篇章

随着科技的飞速发展&#xff0c;展馆行业也在不断寻求创新和突破。展馆漫游可视化和智慧展厅的出现&#xff0c;为展馆行业带来了全新的发展机遇。本文将围绕这两个主题&#xff0c;探讨它们如何改变传统展览模式&#xff0c;开启未来展览新篇章。 一、展馆漫游可视化&#xff…

Ubuntu 20.4镜像国内地址下载较快

Ubuntu20.04版本比较稳定&#xff0c;部署OJ大都用这个版本。 推荐阿里云镜像点&#xff0c;点进去根据你的电脑版本下载iso后缀那个 ubuntu-releases-20.04安装包下载_开源镜像站-阿里云 下载速度较快 其他版本 http://mirrors.aliyun.com/ubuntu-releases/ 如果使用云服务…

C语言/C++雷霆战机代码(终极版)

#include <stdio.h> #include <easyx.h> #include <time.h> #include <Mmsystem.h> #pragma comment(lib,"winmm.lib") #define WIDTH 600 #define HEIGHT 850 #define bullet_max 5000 //我方飞机子弹最大量 #define enemy_bul_ma…

Instagram账号被封?必须了解的原因与防封技巧

您是否曾因 Instagram 帐户被暂停封禁而感到沮丧&#xff1f;这是一个常见问题&#xff0c;了解您的帐户被暂停的原因以及如何恢复帐户至关重要。 在本文中&#xff0c;我们将深入探讨 Instagram 帐户被封停的常见原因&#xff0c;并探讨重新获得访问权限的步骤。这个方法对于管…

源码订货系统的优势

源码订货系统是一种企业购买后可以获得源代码的订货系统&#xff0c;它可以不受软件厂商的规模、发展而修改和使用。与SaaS订货系统相比&#xff0c;核货宝为您分享源码订货系统的四大优势&#xff1a; 一是开放性&#xff1a;源码订货系统是开源的&#xff0c;用户可以掌握源代…

数据结构---算法的时间复杂度

文章目录 前言计算机重要存储数据结构与算法数据结构概念算法 数据库概念 算法的复杂度时间复杂度概念为什么有时间复杂度大O渐进表示法时间复杂度实例实例1&#xff1a;时间复杂度&#xff1a;O&#xff08;N&#xff09;实例2&#xff1a;这里输入参数是不确定的所以 时间复杂…

期货开平规则(期货交易开平规则解析)

什么是期货开平规则 期货开平规则&#xff0c;简单来说是指期货交易中的开仓和平仓所遵循的一系列规定。具体而言&#xff0c;开仓是指买入或卖出期货合约&#xff0c;建立一个新的持仓&#xff1b;平仓则是指买入或卖出相应数量的期货合约&#xff0c;用以解除原有持仓。开平…

MapReduce编程:Join应用

1. Reduce Join Map 端的主要工作&#xff1a;为来自不同表或文件的 key/value 对&#xff0c;打标签以区别不同来源的记录。然后用连接字段作为key &#xff0c;其余部分和新加的标志作为 value &#xff0c;最后进行输出。 Reduce 端的主要工作&#xff1a;在 Reduce 端…

解决IDEA编译/启动报错:Abnormal build process termination

报错信息 报错信息如下&#xff1a; Abnormal build process termination: "D:\Software\Java\jdk\bin\java" -Xmx3048m -Djava.awt.headlesstrue -Djava.endorsed.dirs\"\" -Djdt.compiler.useSingleThreadtrue -Dpreload.project.path………………很纳…

Mybatis之增删改查

一、引言 书接上回&#xff0c;我们在了解完mybatis之后&#xff0c;肯定要知道怎么使用&#xff0c;本文就来详细讲解Mybatis的增删改查事务&#xff0c;还不了解怎么配置mybatis的童鞋可以去这篇文章了解一下通俗易懂讲解javaweb之mybatis-CSDN博客 二、Mybatis——增 举例…
最新文章