ASP.NET Core如何通过IOperationFilter遍历依赖树为OpenAPI加指定请求头
解决方案
我们不需要实际实例化服务来检测依赖,直接通过服务注册元数据递归遍历依赖树即可,同时规避了Scoped服务在根容器解析抛出异常的问题。
改造后的IOperationFilter完整代码
using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; using System.Collections.Concurrent; using System.Reflection; using Microsoft.Extensions.DependencyInjection; public class AddPrimaryHeadersOperationFilter : IOperationFilter { // 缓存类型检测结果,避免重复遍历+防止循环依赖栈溢出 private readonly ConcurrentDictionary<Type, bool> _dependencyCheckCache = new(); private readonly IServiceCollection _serviceRegistrations; // 直接注入服务注册集合,不需要IServiceProvider public AddPrimaryHeadersOperationFilter(IServiceCollection serviceRegistrations) { _serviceRegistrations = serviceRegistrations; } public void Apply(OpenApiOperation operation, OperationFilterContext context) { if (ActionDependOnPrimaryService(context.MethodInfo)) { operation.Parameters ??= new List<OpenApiParameter>(); operation.Parameters.Add(new OpenApiParameter { Name = "Primary-Id", In = ParameterLocation.Header, Required = false, Schema = new OpenApiSchema { Type = "int" } }); } } private bool ActionDependOnPrimaryService(MethodInfo actionMethod) { // 你已经实现的控制器自身构造依赖、FromServices参数检测逻辑可以放在这里 foreach (var parameter in actionMethod.GetParameters()) { if (HasPrimaryServiceDependency(parameter.ParameterType)) { return true; } } return false; } private bool HasPrimaryServiceDependency(Type serviceType) { // 命中缓存直接返回 if (_dependencyCheckCache.TryGetValue(serviceType, out var hasDependency)) return hasDependency; // 直接匹配目标服务接口 if (serviceType == typeof(IPrimaryService)) { _dependencyCheckCache[serviceType] = true; return true; } // 查找当前服务类型的注册描述,取最后一个注册符合ASP.NET Core默认覆盖规则 var serviceDesc = _serviceRegistrations.LastOrDefault(d => d.ServiceType == serviceType); // 非自定义注册的服务(框架内置服务)直接判定为无依赖 if (serviceDesc?.ImplementationType == null) { _dependencyCheckCache[serviceType] = false; return false; } // 遍历实现类所有构造函数的参数,递归检测依赖 foreach (var constructor in serviceDesc.ImplementationType.GetConstructors()) { foreach (var param in constructor.GetParameters()) { if (HasPrimaryServiceDependency(param.ParameterType)) { _dependencyCheckCache[serviceType] = true; return true; } } } // 无匹配依赖 _dependencyCheckCache[serviceType] = false; return false; } }
说明
- 无需修改原有服务注册逻辑,
IServiceCollection会自动注入到过滤器的构造函数中 - 支持任意层级的构造函数注入依赖检测,符合你不需要处理工厂获取服务的要求
- 缓存逻辑同时解决了重复检测性能问题和循环依赖栈溢出问题
- 你原有省略的控制器构造依赖、
[FromServices]校验逻辑可以直接整合到ActionDependOnPrimaryService方法中
内容的提问来源于stack exchange,提问作者vernou
相关产品推荐
相关产品推荐

