首页 新闻 会员 周边

全局IAsyncActionFilter中设置的Order属性无效

0
悬赏园豆:100 [已解决问题] 解决于 2024-03-12 11:28

我定义了两个异步的IAsyncActionFilter,分别用于参数校验以及返回结果包装;

我遇到的问题是:两个筛选器的调用顺序并没有按照 Order大小即先执行DataValidationFilter.Before 然后执行SucceedResultFilter.Before而是按照注入服务时调用AddDataValidation和AddUnifyResult的先后顺序执行。

例如先调用AddUnifyResult则先执行SucceedResultFilter.Before

筛选器定义如下

// 参数校验
public class DataValidationFilter(IOptions<ApiBehaviorOptions> options): IAsyncActionFilter, IOrderedFilter
{
    private const int FilterOrder = -1000;
    private readonly ApiBehaviorOptions _apiBehaviorOptions = options.Value;
    public int Order => FilterOrder;
    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
          // do something
    }
}

// 返回结果包装
public class SucceedResultFilter : IAsyncActionFilter, IOrderedFilter
{
    private const int FilterOrder = 8888;

    public int Order => FilterOrder;

    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
       // do something
    }

添加两个筛选器的方式如下

/// <summary>
/// 添加规范化结果服务
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
public static IServiceCollection AddUnifyResult(this IServiceCollection services)
{
    services.Configure<MvcOptions>(options =>
    {
        options.Filters.Add<SucceedResultFilter>();
        options.Conventions.Add(new UnifyResultApplicationModelConvention());
    });

    return services;
}

/// <summary>
/// 添加全局数据验证
/// </summary>
public static IServiceCollection AddDataValidation(this IServiceCollection services, Action<DataValidationOptions>? options = null)
{
    var configureOptions = new DataValidationOptions();
    options?.Invoke(configureOptions);

    if (configureOptions.GlobalEnabled)
    {
        services.Configure<ApiBehaviorOptions>(opt =>
        {
            opt.SuppressMapClientErrors = configureOptions.SuppressMapClientErrors;
            opt.SuppressModelStateInvalidFilter = configureOptions.SuppressModelStateInvalidFilter;
        });

        services.Configure<MvcOptions>(opt =>
        {
            opt.Filters.Add<DataValidationFilter>();
            opt.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = configureOptions.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes;
        });
    }

    return services;
}
DengQinwen的主页 DengQinwen | 初学一级 | 园豆:102
提问于:2024-03-09 14:48
< >
分享
最佳答案
0

你可以debug 看一下 ControllerActionDescriptor 上面的FilterDescriptors属性 这个list里面的filters 基本就等于最终执行的filters(多少个,和顺序)

ControllerActionDescriptor就是 ControllerBase.ControllerContext.ActionDescriptor属性.

收获园豆:60
czd890 | 专家六级 |园豆:14412 | 2024-03-11 15:43

一开始就看过了,这个顺序就是Filter的注入顺序

DengQinwen | 园豆:102 (初学一级) | 2024-03-12 10:02

@DengQinwen:
用 options.Filters.Add<TFilter>(order);

czd890 | 园豆:14412 (专家六级) | 2024-03-12 10:46
其他回答(1)
0

看起来你正在尝试通过设置Order属性来控制IAsyncActionFilter的执行顺序,但这不起作用。实际上,根据官方文档,筛选器的执行顺序是由注册到 DI 容器的顺序决定的。也就是说,最先注册到DI容器的筛选器将首先被执行。

然而,Order属性在某些情况下可以影响筛选器的执行顺序。特别是,在一个组中筛选器的执行顺序将由Order属性确定。这意味着在同一个组中,具有较低Order值的筛选器将首先执行。

如果你想要DataValidationFilter筛选器在SucceedResultFilter筛选器之前执行,你可以尝试让他们处于同一组,并且为DataValidationFilter筛选器设置较低的Order值。

在你的代码中,DataValidationFilterOrder值已经比SucceedResultFilterOrder值小,所以你需要确保他们注册到同一组。你可以通过创建自定义筛选器提供程序并将其添加到MVC选项的FilterProviders集合来实现这一点。

下面是一个如何实现自定义筛选器提供程序的示例:

public class CustomFilterProvider : IFilterProvider
{
    public int Order => -1000;  // Make sure our provider runs first

    public void OnProvidersExecuting(FilterProviderContext context)
    {
        // logic here
    }

    public void OnProvidersExecuted(FilterProviderContext context)
    {
        // logic here
    }
}

然后在你的Startup.cs文件中添加这个提供程序:

services.AddControllers(options =>
{
    options.Filters.Add(new DataValidationFilter());
    options.Filters.Add(new SucceedResultFilter());

    options.FilterProviders.Clear();
    options.FilterProviders.Add(new CustomFilterProvider());
});

这样,你就可以通过Order属性来控制筛选器的执行顺序了。请注意,这只是一个示例,并可能需要根据你的具体需求进行调整。

收获园豆:40
npe0 | 园豆:1299 (小虾三级) | 2024-03-11 14:27
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册