ASP.NET 6+中如何让[FromQuery]支持多格式参数名匹配?
在ASP.NET 6+中实现[FromQuery]参数名的自动兼容(下划线/连字符)
完全可以在参数匹配的早期管道阶段介入处理,通过自定义值提供器(ValueProvider)或者中间件两种方式,让[FromQuery] bool testValue自动匹配testValue、test-value、test_value三种查询参数格式。
方案一:自定义QueryStringValueProvider(推荐)
这种方式仅在模型绑定阶段生效,不会修改原始请求的查询字符串,更符合ASP.NET的设计规范。
1. 实现自定义值提供器
继承QueryStringValueProvider,重写GetValue方法,同时检查原始参数名、kebab-case(连字符分隔)、snake_case(下划线分隔)三种格式的查询键:
public class FlexibleQueryStringValueProvider : QueryStringValueProvider { public FlexibleQueryStringValueProvider(BindingSource bindingSource, QueryString queryString, CultureInfo culture) : base(bindingSource, queryString, culture) { } public override ValueProviderResult GetValue(string key) { // 优先匹配原始参数名 var result = base.GetValue(key); if (result != ValueProviderResult.None) return result; // 转换为kebab-case格式匹配(如testValue → test-value) var kebabKey = string.Concat(key.Select((c, i) => i > 0 && char.IsUpper(c) ? $"-{char.ToLower(c)}" : c.ToString())); result = base.GetValue(kebabKey); if (result != ValueProviderResult.None) return result; // 转换为snake_case格式匹配(如testValue → test_value) var snakeKey = string.Concat(key.Select((c, i) => i > 0 && char.IsUpper(c) ? $"_{char.ToLower(c)}" : c.ToString())); return base.GetValue(snakeKey); } }
2. 实现值提供器工厂
创建工厂类用于生成自定义值提供器:
public class FlexibleQueryStringValueProviderFactory : IValueProviderFactory { public Task CreateValueProviderAsync(ValueProviderFactoryContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); var query = context.ActionContext.HttpContext.Request.Query; if (!query.Any()) return Task.CompletedTask; var valueProvider = new FlexibleQueryStringValueProvider( BindingSource.Query, query, CultureInfo.CurrentCulture); context.ValueProviders.Add(valueProvider); return Task.CompletedTask; } }
3. 替换默认值提供器
在Program.cs中注册自定义工厂,替换默认的查询字符串值提供器:
builder.Services.AddControllers(options => { // 移除默认的QueryStringValueProviderFactory var defaultFactory = options.ValueProviderFactories .FirstOrDefault(f => f is QueryStringValueProviderFactory); if (defaultFactory != null) { options.ValueProviderFactories.Remove(defaultFactory); } // 添加自定义工厂 options.ValueProviderFactories.Add(new FlexibleQueryStringValueProviderFactory()); });
方案二:使用中间件重写查询字符串
这种方式在请求管道的更早阶段修改查询字符串,将所有带-和_的键转换为驼峰格式,让默认的模型绑定器直接匹配:
1. 实现中间件
public class QueryStringNormalizationMiddleware { private readonly RequestDelegate _next; public QueryStringNormalizationMiddleware(RequestDelegate next) { _next = next; } public async Task InvokeAsync(HttpContext context) { var queryBuilder = new QueryBuilder(); foreach (var (key, values) in context.Request.Query) { // 将test-value、test_value转换为testValue var normalizedKey = NormalizeQueryKey(key); queryBuilder.Add(normalizedKey, values.ToArray()); } // 替换原始查询字符串 context.Request.QueryString = queryBuilder.ToQueryString(); await _next(context); } private string NormalizeQueryKey(string key) { var sb = new StringBuilder(); bool capitalizeNext = false; foreach (var c in key) { if (c == '-' || c == '_') { capitalizeNext = true; continue; } sb.Append(capitalizeNext ? char.ToUpper(c) : c); capitalizeNext = false; } return sb.ToString(); } }
2. 注册中间件
在Program.cs中添加中间件(注意要放在UseRouting之前):
app.UseMiddleware<QueryStringNormalizationMiddleware>(); app.UseRouting();
两种方案都能实现需求,其中方案一的侵入性更低,仅针对模型绑定逻辑生效,更推荐在生产环境使用。
内容的提问来源于stack exchange,提问作者CodeAngry
相关产品推荐
相关产品推荐

