You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 13:24:03