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

.NET Core GroupingCodeFilter无查询参数时失效,DynamicTaskAttribute影响求助

问题分析

你的核心问题是:GroupingCodeFilter仅在传递查询参数或注释DynamicTaskAttribute时能正常工作,否则会抛出The given key 'grouping' was not present in the dictionary异常。

根源在于过滤器执行顺序:DynamicTaskAttribute的执行时机早于GroupingCodeFilter,当它尝试读取httpContext.Items["grouping"]时,你的过滤器还未完成该值的设置,导致键不存在的错误。而传递查询参数时,DynamicTaskAttribute可能自身会直接从查询参数取值;注释它后,过滤器能正常执行并设置值,后续代码即可正确读取。


解决方案

方案1:调整GroupingCodeFilter的执行顺序

通过设置Order属性,让你的过滤器优先于DynamicTaskAttribute执行(数值越小,执行优先级越高,默认过滤器Order为0):

修改过滤器类

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class GroupingCodeFilter : Attribute, IAsyncActionFilter
{
    // 设置比默认值更小的Order,确保先执行
    public int Order { get; set; } = -10;

    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        var httpContext = context.HttpContext;
        var request = httpContext.Request;

        if (request.Query.TryGetValue("grouping", out var groupingFromQuery))
        {
            httpContext.Items["grouping"] = groupingFromQuery.ToString();
        }
 
        else if (context.ActionArguments.TryGetValue("model", out var value) &&
                 value is GridParamsModel gridModel &&
                 gridModel.ParameterDictionary != null &&
                 gridModel.ParameterDictionary.TryGetValue("groupingCode", out var groupingCodeObj))
        {
            var groupingCode = groupingCodeObj?.ToString();
            if (!string.IsNullOrEmpty(groupingCode))
            {
                httpContext.Items["grouping"] = groupingCode;
            }
        }

        await next();
    }
}

在控制器方法上指定Order

[HttpPost("GetContent")]
[GroupingCodeFilter(Order = -10)]
[DynamicTask(typeof(...), "GetDynamicTaskAttributeID", "grouping")]
public async Task<IActionResult> GetContent([FromBody] GridParamsModel model)
{}

如果DynamicTaskAttribute也设置了Order,确保GroupingCodeFilter的Order值比它更小即可。


方案2:改用ResourceFilter提前获取值

ResourceFilter的执行时机早于所有ActionFilter和模型绑定,可以提前读取请求体并解析值,避免顺序问题:

实现ResourceFilter

public class GroupingCodeResourceFilter : IAsyncResourceFilter
{
    private readonly IModelMetadataProvider _modelMetadataProvider;
    private readonly IModelBinderFactory _modelBinderFactory;

    public GroupingCodeResourceFilter(IModelMetadataProvider modelMetadataProvider, IModelBinderFactory modelBinderFactory)
    {
        _modelMetadataProvider = modelMetadataProvider;
        _modelBinderFactory = modelBinderFactory;
    }

    public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next)
    {
        var httpContext = context.HttpContext;
        var request = httpContext.Request;

        // 优先检查查询参数
        if (request.Query.TryGetValue("grouping", out var groupingFromQuery))
        {
            httpContext.Items["grouping"] = groupingFromQuery.ToString();
        }
        else if (request.ContentType?.Contains("application/json") == true)
        {
            // 启用请求体缓冲,允许重复读取
            request.EnableBuffering();
            var bodyText = await new StreamReader(request.Body).ReadToEndAsync();
            request.Body.Position = 0; // 重置流位置,不影响后续模型绑定

            var gridModel = JsonSerializer.Deserialize<GridParamsModel>(bodyText);
            if (gridModel?.ParameterDictionary != null &&
                gridModel.ParameterDictionary.TryGetValue("groupingCode", out var groupingCodeObj))
            {
                var groupingCode = groupingCodeObj?.ToString();
                if (!string.IsNullOrEmpty(groupingCode))
                {
                    httpContext.Items["grouping"] = groupingCode;
                }
            }
        }

        await next();
    }
}

注册并使用过滤器

在Program.cs(或Startup.cs)中注册:

builder.Services.AddScoped<GroupingCodeResourceFilter>();

控制器方法上使用:

[HttpPost("GetContent")]
[ServiceFilter(typeof(GroupingCodeResourceFilter))]
[DynamicTask(typeof(...), "GetDynamicTaskAttributeID", "grouping")]
public async Task<IActionResult> GetContent([FromBody] GridParamsModel model)
{}

方案3:修改DynamicTaskAttribute的执行时机

如果你有权限修改DynamicTaskAttribute的代码,可将其改为IAsyncActionFilter并设置更大的Order值,确保它在GroupingCodeFilter执行后再读取httpContext.Items["grouping"]。


额外排查点
  1. 验证请求体中的GridParamsModel.ParameterDictionary确实包含groupingCode键,可在过滤器中添加断点或日志输出确认。
  2. 检查请求体格式是否符合JSON规范,确保模型绑定能正确解析GridParamsModel。

内容的提问来源于stack exchange,提问作者Ishani Bhatt

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 15:55:54