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

.NET 5查询字符串参数绑定字典时自动补[eq]运算符方案问询

实现方案

方案1:中间件全局改写查询参数

虽然context.Request.Query默认是只读的,但可以直接对它重新赋值为新构造的QueryCollection对象,实现全局的查询参数归一化处理,步骤如下:

  1. 新建中间件类,处理查询参数转换逻辑
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;

public class QueryOperatorNormalizationMiddleware
{
    private readonly RequestDelegate _next;

    public QueryOperatorNormalizationMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        var originalQuery = context.Request.Query;
        var modifiedQuery = new Dictionary<string, StringValues>();

        foreach (var (key, value) in originalQuery)
        {
            // 判断是否已经带有运算符后缀
            if (!key.Contains('[') && !key.Contains(']'))
            {
                // 无运算符的参数追加[eq]后缀
                var newKey = $"{key}[eq]";
                modifiedQuery[newKey] = value;
            }
            else
            {
                // 已有运算符的参数保留原键
                modifiedQuery[key] = value;
            }
        }

        // 替换原查询参数集合
        context.Request.Query = new QueryCollection(modifiedQuery);

        await _next(context);
    }
}
  1. 在Program.cs中注册中间件,注意要放在路由、控制器相关中间件之前:
var builder = WebApplication.CreateBuilder(args);
// 其他服务注册...

var app = builder.Build();

// 注册在最前面或者UseRouting之前即可
app.UseMiddleware<QueryOperatorNormalizationMiddleware>();

app.UseRouting();
// 其他中间件...
app.MapControllers();

app.Run();

该方案全局生效,所有接口的查询参数都会自动适配规则,无需修改模型定义,只需保留字典类型的属性即可正常绑定。

方案2:自定义模型绑定器(更灵活)

如果不需要全局生效,只针对指定的请求模型生效,可以使用自定义模型绑定器,不需要修改全局查询参数:

  1. 实现自定义模型绑定器
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.Primitives;

public class OperatorDictionaryModelBinder : IModelBinder
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (bindingContext.ModelType != typeof(Dictionary<string, int>))
        {
            return Task.CompletedTask;
        }

        var modelName = bindingContext.ModelName;
        var resultDict = new Dictionary<string, int>();

        // 处理带运算符的参数,比如price[gt]
        var matchingKeys = bindingContext.HttpContext.Request.Query
            .Where(q => q.Key.StartsWith($"{modelName}[", StringComparison.OrdinalIgnoreCase) && q.Key.EndsWith("]"))
            .ToList();

        foreach (var (key, value) in matchingKeys)
        {
            var op = key.Substring(modelName.Length + 1, key.Length - modelName.Length - 2);
            if (int.TryParse(value, out var numValue))
            {
                resultDict[op.ToLower()] = numValue;
            }
        }

        // 处理无运算符的默认参数,比如price=10
        var defaultValue = bindingContext.ValueProvider.GetValue(modelName);
        if (defaultValue != ValueProviderResult.None && int.TryParse(defaultValue.FirstValue, out var eqValue))
        {
            resultDict["eq"] = eqValue;
        }

        bindingContext.Result = ModelBindingResult.Success(resultDict);
        return Task.CompletedTask;
    }
}
  1. 在请求模型的属性上指定绑定器即可:
public class BookRequestModel
{
    [FromQuery]
    [ModelBinder(BinderType = typeof(OperatorDictionaryModelBinder))]
    public Dictionary<string, int> Price { get; set; }
}

该方案不会影响其他接口的查询参数逻辑,适合仅部分接口需要该规则的场景。

选型建议

  • 全项目统一使用查询运算符规则选方案1
  • 仅部分接口需要该能力选方案2

内容的提问来源于stack exchange,提问作者adnan kamili

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 22:09:04