ASP.NET Core控制器SwaggerResponse特性优化方案咨询
ASP.NET Core 精简Swagger响应特性的可行方案
一、自定义通用错误响应特性
将重复的4xx错误响应封装为自定义特性,配合Swagger的IOperationFilter批量注入响应配置,控制器方法只需保留特定的成功响应+自定义特性即可。
实现代码
- 定义自定义特性:
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = false)] public class CommonSwaggerErrorResponsesAttribute : Attribute { }
- 编写配套的OperationFilter:
public class CommonErrorResponsesFilter : IOperationFilter { public void Apply(OpenApiOperation operation, OperationFilterContext context) { var hasCommonErrorsAttr = context.MethodInfo.GetCustomAttributes(typeof(CommonSwaggerErrorResponsesAttribute), true).Any() || context.ControllerType.GetCustomAttributes(typeof(CommonSwaggerErrorResponsesAttribute), true).Any(); if (!hasCommonErrorsAttr) return; // 添加400响应 operation.Responses.Add("400", new OpenApiResponse { Description = "InvalidationError", Content = new Dictionary<string, OpenApiMediaType> { ["application/json"] = new OpenApiMediaType { Schema = context.SchemaGenerator.GenerateSchema(typeof(OperationResult<ValidationError>), context.SchemaRepository) } } }); // 批量添加其他通用错误响应 var commonErrors = new Dictionary<string, (string Desc, Type ResultType)> { ["401"] = ("Not Authorised", typeof(OperationResult<Error>)), ["403"] = ("No access to execute action", typeof(OperationResult<Error>)), ["404"] = ("Not found", typeof(OperationResult<Error>)), ["405"] = ("Method not allowed", typeof(OperationResult<Error>)), ["415"] = ("Medias type not allowed", typeof(OperationResult<Error>)) }; foreach (var (code, errorInfo) in commonErrors) { if (!operation.Responses.ContainsKey(code)) { operation.Responses.Add(code, new OpenApiResponse { Description = errorInfo.Desc, Content = new Dictionary<string, OpenApiMediaType> { ["application/json"] = new OpenApiMediaType { Schema = context.SchemaGenerator.GenerateSchema(errorInfo.ResultType, context.SchemaRepository) } } }); } } } }
- 注册过滤器并在控制器中使用:
// Program.cs中注册过滤器 builder.Services.AddSwaggerGen(c => { c.OperationFilter<CommonErrorResponsesFilter>(); }); // 控制器方法简化写法 [SwaggerResponse(200, "Successful", typeof(OperationResult<List<GetAllEventDTO>>))] [CommonSwaggerErrorResponses] public async Task<IActionResult> AllEvent() { // 方法实现 }
二、使用API约定(ApiConvention)
定义包含通用响应的API约定,控制器或方法应用约定后自动继承所有配置的响应特性,无需逐个添加。
实现代码
- 定义API约定:
public static class DefaultApiConventions { [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(OperationResult<ValidationError>))] [ProducesResponseType(StatusCodes.Status401Unauthorized, Type = typeof(OperationResult<Error>))] [ProducesResponseType(StatusCodes.Status403Forbidden, Type = typeof(OperationResult<Error>))] [ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(OperationResult<Error>))] [ProducesResponseType(StatusCodes.Status405MethodNotAllowed, Type = typeof(OperationResult<Error>))] [ProducesResponseType(StatusCodes.Status415UnsupportedMediaType, Type = typeof(OperationResult<Error>))] public static void Get() { } }
- 在控制器或方法上应用约定:
// 全局应用到控制器 [ApiConventionType(typeof(DefaultApiConventions))] public class EventController : ControllerBase { // 仅需补充特定的响应描述和DTO类型 [SwaggerResponse(200, "Successful", typeof(OperationResult<List<GetAllEventDTO>>))] public async Task<IActionResult> AllEvent() { // 方法实现 } } // 或仅在单个方法上应用 [ApiConventionMethod(typeof(DefaultApiConventions), nameof(DefaultApiConventions.Get))] [SwaggerResponse(200, "Successful", typeof(OperationResult<List<GetAllEventDTO>>))] public async Task<IActionResult> AllEvent() { // 方法实现 }
三、全局OperationFilter自动注入通用响应
如果所有接口都需要这些通用错误响应,可直接编写全局过滤器,无需在控制器添加任何额外特性,自动为所有接口注入通用4xx响应。
实现代码
public class GlobalErrorResponsesFilter : IOperationFilter { public void Apply(OpenApiOperation operation, OperationFilterContext context) { var commonErrors = new Dictionary<string, (string Desc, Type ResultType)> { ["400"] = ("InvalidationError", typeof(OperationResult<ValidationError>)), ["401"] = ("Not Authorised", typeof(OperationResult<Error>)), ["403"] = ("No access to execute action", typeof(OperationResult<Error>)), ["404"] = ("Not found", typeof(OperationResult<Error>)), ["405"] = ("Method not allowed", typeof(OperationResult<Error>)), ["415"] = ("Medias type not allowed", typeof(OperationResult<Error>)) }; foreach (var (code, errorInfo) in commonErrors) { if (!operation.Responses.ContainsKey(code)) { operation.Responses.Add(code, new OpenApiResponse { Description = errorInfo.Desc, Content = new Dictionary<string, OpenApiMediaType> { ["application/json"] = new OpenApiMediaType { Schema = context.SchemaGenerator.GenerateSchema(errorInfo.ResultType, context.SchemaRepository) } } }); } } } }
注册过滤器后,控制器方法仅需保留成功响应配置:
[SwaggerResponse(200, "Successful", typeof(OperationResult<List<GetAllEventDTO>>))] public async Task<IActionResult> AllEvent() { // 方法实现 }
四、封装泛型响应特性(辅助精简)
针对OperationResult<T>的统一格式,封装泛型响应特性,减少重复的typeof声明:
public class SwaggerTypedResponseAttribute : SwaggerResponseAttribute { public SwaggerTypedResponseAttribute(int statusCode, string description, Type dataType) : base(statusCode, description, typeof(OperationResult<>).MakeGenericType(dataType)) { } }
用法示例:
[SwaggerTypedResponse(200, "Successful", typeof(List<GetAllEventDTO>))] [SwaggerTypedResponse(400, "InvalidationError", typeof(ValidationError))] public async Task<IActionResult> AllEvent() { // 方法实现 }
内容的提问来源于stack exchange,提问作者user21736604
相关产品推荐
相关产品推荐

