.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"]。
- 验证请求体中的
GridParamsModel.ParameterDictionary确实包含groupingCode键,可在过滤器中添加断点或日志输出确认。 - 检查请求体格式是否符合JSON规范,确保模型绑定能正确解析
GridParamsModel。
内容的提问来源于stack exchange,提问作者Ishani Bhatt

