之前写过使用自定义返回类的方式来统一接口数据返回格式,.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
在代码中进行判断,当响应的类型是 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的接口也不会重复包装: