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

如何将Swashbuckle .NET 6操作过滤器改为支持多类型的泛型过滤器?

解决泛型Swashbuckle操作过滤器的反射添加问题

你遇到的错误核心原因是:泛型参数需要编译时确定的类型,而foreach循环中的type是运行时变量,无法直接作为泛型参数传入OperationFilter<>方法。以下是两种可行的解决方案:


方案一:通过反射创建泛型过滤器实例

步骤1:修正类型获取逻辑

你之前的代码获取的是IMarkerInterface的实例列表,但我们需要的是类型本身而非实例。同时,判断接口实现应使用IsAssignableFrom(IsSubclassOf仅适用于类继承,无法识别接口实现):

var types = typeof(IMarkerInterface)
            .Assembly.GetTypes()
            .Where(t => typeof(IMarkerInterface).IsAssignableFrom(t) && !t.IsAbstract && t.IsClass)
            .ToList();

步骤2:修正泛型过滤器的约束

原过滤器的泛型约束where T : IOperationFilter, new()存在错误,T应该是IMarkerInterface的实现类,而非IOperationFilter。修正后:

public class ArraySettingsOperationFilter<T> : IOperationFilter where T : IMarkerInterface, new()
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        if (operation.RequestBody != null && operation.RequestBody.Content.TryGetValue("multipart/form-data", out var openApiMediaType))
        {
            var options = new JsonSerializerOptions { WriteIndented = true };
            var array = new OpenApiArray
            {
                new OpenApiString(JsonSerializer.Serialize(new T(), options)),
            };
            // 增加空判断避免空引用异常
            if (openApiMediaType.Schema.Properties.TryGetValue("Competences", out var property))
            {
                property.Example = array;
            }
        }
    }
}

步骤3:通过反射添加泛型过滤器

使用MakeGenericType创建泛型过滤器的具体类型,再通过Activator.CreateInstance生成实例,最后调用非泛型的OperationFilter方法添加:

services.AddSwaggerGen(c =>
{
    foreach (var type in types)
    {
        // 创建泛型过滤器类型
        var filterGenericType = typeof(ArraySettingsOperationFilter<>).MakeGenericType(type);
        // 创建过滤器实例
        var filterInstance = Activator.CreateInstance(filterGenericType) as IOperationFilter;
        
        if (filterInstance != null)
        {
            c.OperationFilter(filterInstance);
        }
    }      
});

方案二:改用非泛型过滤器(更简洁易维护)

放弃泛型,将目标类型通过构造函数传入过滤器,避免反射处理泛型的复杂度:

步骤1:创建非泛型过滤器

public class ArraySettingsOperationFilter : IOperationFilter
{
    private readonly Type _targetType;
    private readonly string _propertyName;

    // 允许自定义属性名,默认使用"Competences"
    public ArraySettingsOperationFilter(Type targetType, string propertyName = "Competences")
    {
        _targetType = targetType;
        _propertyName = propertyName;
    }

    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        if (operation.RequestBody == null || !operation.RequestBody.Content.TryGetValue("multipart/form-data", out var openApiMediaType))
            return;

        var options = new JsonSerializerOptions { WriteIndented = true };
        // 创建目标类型实例并序列化
        var targetInstance = Activator.CreateInstance(_targetType);
        var array = new OpenApiArray
        {
            new OpenApiString(JsonSerializer.Serialize(targetInstance, options)),
        };

        if (openApiMediaType.Schema.Properties.TryGetValue(_propertyName, out var property))
        {
            property.Example = array;
        }
    }
}

步骤2:直接添加过滤器实例

services.AddSwaggerGen(c =>
{
    var types = typeof(IMarkerInterface)
                .Assembly.GetTypes()
                .Where(t => typeof(IMarkerInterface).IsAssignableFrom(t) && !t.IsAbstract && t.IsClass)
                .ToList();

    foreach (var type in types)
    {
        // 直接创建过滤器实例并添加
        c.OperationFilter(new ArraySettingsOperationFilter(type));
        // 如需指定不同属性名,可传入第二个参数:
        // c.OperationFilter(new ArraySettingsOperationFilter(type, "YourPropertyName"));
    }      
});

关键说明

  • 原代码中IsSubclassOf(typeof(IMarkerInterface))无法正确识别接口实现类,必须替换为typeof(IMarkerInterface).IsAssignableFrom(t)。
  • 方案二更简洁易维护,避免了泛型反射的复杂性,同时支持自定义属性名,灵活性更高。

内容的提问来源于stack exchange,提问作者live coder

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 15:32:17