.NET Core OData查询过滤器含特殊字符解析失败求助
解决OData查询过滤器含特殊字符的解析失败问题
问题场景
我们通过OData查询过滤器向WebAPI发起请求,示例请求如下:
https://localhost:44372/v1/odata/xxx/xxxx/xxxxxx?$select=type_of_secur&$filter=type_of_secur eq 'Ability & ABS'
或
https://localhost:44372/v1/odata/xxx/xxxx/xxxxxx?$select=type_of_secur&$filter=type_of_secur in ('Ability & ABS')
其中type_of_secur是枚举类型,需要根据过滤器中的文本匹配枚举字符串,关联数据库中的整数值返回结果。但当过滤器值包含&这类特殊字符时,请求直接解析失败,报错:
"errors": { "Invalid request parameters": [ "Invalid OData query '? There is an unterminated string literal at position 37 in 'type_of_secur eq 'Corporate CMOs ?'.'" ] }
尝试自定义FilterBinder处理特殊字符,但未编码的请求根本无法进入自定义Binder的逻辑,只有使用编码后的字符(如type_of_secur eq 'Corporate CMOs %26 ABS')时,才会触发CustomFilterBinder的BindConstantNode方法:
public class CustomFilterBinder : FilterBinder { public override Expression BindConstantNode(Microsoft.OData.UriParser.ConstantNode constantNode) { // 自定义逻辑占位 } }
核心原因
OData URI中的&属于HTTP URI的保留字符,未编码的情况下,HTTP服务器会将其解析为查询参数的分隔符,导致OData解析器拿到的过滤器字符串被截断,直接判定为未闭合的字符串字面量,报错终止解析,根本无法到达自定义Binder的处理环节。
解决方案
1. 强制对过滤器值中的特殊字符进行URI编码
这是前置必要条件,必须在发起请求前对过滤器中的特殊字符(如&、=、?等)进行URI编码:
- C#发起请求时,使用
Uri.EscapeDataString处理:string filterValue = "Ability & ABS"; string encodedValue = Uri.EscapeDataString(filterValue); string filterClause = $"type_of_secur eq '{encodedValue}'"; // 拼接完整请求URL - 前端JavaScript中使用
encodeURIComponent处理:const filterValue = "Ability & ABS"; const encodedValue = encodeURIComponent(filterValue); const filterClause = `type_of_secur eq '${encodedValue}'`;
2. 在自定义FilterBinder中处理枚举匹配
当请求携带编码后的参数到达服务器后,OData解析器会自动解码参数值,此时可以在BindConstantNode中处理枚举字符串到数据库整数值的映射:
public class CustomFilterBinder : FilterBinder { public override Expression BindConstantNode(ConstantNode constantNode) { // 仅处理枚举类型的常量节点 if (constantNode.Type == typeof(string) && constantNode.Value != null) { string enumString = constantNode.Value.ToString(); // 将枚举字符串转换为对应的数据库整数值 if (Enum.TryParse<SecurityType>(enumString, out var securityType)) { int dbValue = (int)securityType; // 返回对应整数值的表达式,后续查询会使用该值匹配数据库列 return Expression.Constant(dbValue, typeof(int)); } } // 其他情况调用基类逻辑 return base.BindConstantNode(constantNode); } }
3. 配置OData启用严格的URI解析
确保OData配置中启用正确的URI解析规则,避免解析异常:
public static IEdmModel GetEdmModel() { ODataConventionModelBuilder builder = new ODataConventionModelBuilder(); // 配置实体集等逻辑 return builder.GetEdmModel(); } public void ConfigureServices(IServiceCollection services) { services.AddControllers().AddOData(options => { options.Select().Filter().OrderBy().Expand().Count().SetMaxTop(null); options.AddRouteComponents("v1/odata", GetEdmModel(), services => { // 替换为自定义FilterBinder services.AddSingleton<FilterBinder, CustomFilterBinder>(); // 配置URI解析器,启用严格模式 services.AddSingleton<ODataUriParserSettings>(new ODataUriParserSettings { EnableCaseInsensitive = true, EnableNoDollarQueryOptions = false }); }); }); }
关键注意事项
- 永远不要跳过URI编码直接处理特殊字符:未编码的请求在到达OData解析器之前就会被HTTP服务器拆解,导致请求本身无效。
- 自定义FilterBinder仅能处理已经被OData解析器正确解析的请求,无法修复因URI格式错误导致的解析失败。
内容的提问来源于stack exchange,提问作者Raajesh Ka
相关产品推荐
相关产品推荐

