在RestFul风格盛行的年代,大部分接口都需要一套统一的数据返回格式,那么我们怎么才能保证使用统一的json数据格式返回呢,下面给大家简单介绍一下:
假如我们需要接口统一返回一下数据格式:
{
"statusCode": 200,
"successful": true,
"message": null,
"data": object
}
json对象中data是返回的实际结果对象,可以是一个对象、一个list、一个字符串、一个数字......
但是整体的json格式要以上面的为准
一般这种情况我们有两种实现方式:
1、自定义一个统一返回类
2、使用过滤器(Filter)实现
下面先介绍第一种,自定义一个接口返回类:
创建对应的接口类和实现类
- ApiResponse.cs//实现类
- IApiResponse.cs://几个相关的接口
IApiResponse.cs
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; }
}
保证了所有相关对象都来自 IApiResponse
接口
ApiResponse.cs
cs
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
};
}
}
分别实现类带有泛型的 ApiResponse<T> 类和 ApiResponse 类
注意在泛型类中,使用运算符重载,实现了 ApiResponse
到 ApiResponse<T>
的隐式转换。
在接口实现处返回一个 ApiResponse<T> 对象:
cs
[HttpGet]
public ApiResponse<UserEntity> Get(string name)
{
var list = new List<UserEntity>()
{
new UserEntity() { Name = "张三" },
new UserEntity(){Name = "李四"}
};
var user = list.Find(p => p.Name == name);
return user == null ? ApiResponse.NotFound() : new ApiResponse<UserEntity>(user);
}
注意看最后一句
return user == null ? ApiResponse.NotFound() : new ApiResponse<UserEntity>(user);
ApiResponse.NotFound()
返回的是一个 ApiResponse
对象
但这接口的返回值明明是 ApiResponse<
UserEntity>
类型呀,这不是类型不一致吗?
不过在 ApiResponse<T>
中,我们定义了一个运算符重载,实现了 ApiResponse
类型到 ApiResponse<T>
的隐式转换,所以就完美解决这个问题,大大减少了代码量。
来看一下最后运行效果:
下一章介绍一下如何通过自定义过滤器的方式实现统一接口返回数据格式: