.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 {
                        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 : IApiResponse
    {
        public T? Data { get; set; }
    }
    public interface IApiErrorResponse
    {
        public Dictionary ErrorData { get; set; }
    }
    public class ApiResponse : IApiResponse {
        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; }
        ///  /// 实现将  隐式转换为  ///  ///  public static implicit operator ApiResponse(ApiResponse apiResponse)
        {
            return new ApiResponse {
                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; }
        ///  /// 可序列化的错误
        /// 用于保存模型验证失败的错误信息 ///  public Dictionary? 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();
});

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

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