.NET中OData V4如何去除枚举命名空间实现查询过滤
问题描述
在.NET中使用OData V4基于枚举字段过滤数据时,希望查询字符串无需包含枚举的完整命名空间。目前使用带命名空间的URL(https://localhost:7282/weatherforecast?$filter=testEnum%20eq%20TestOData.TestEnum%271%27)可正常过滤,但仅传递枚举值的URL(https://localhost:7282/weatherforecast?$filter=testEnum%20eq%20%271%27)会抛出ODataException异常。
现有代码
启动代码
using Microsoft.AspNetCore.OData; var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers().AddOData(opt => opt.Select().Filter().OrderBy()); var app = builder.Build(); app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run();
枚举定义
public enum TestEnum { Test1, Test2, Test3 }
控制器代码
[ApiController] [Route("[controller]")] public class WeatherForecastController : ControllerBase { private static readonly string[] Summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; private readonly ILogger<WeatherForecastController> _logger; public WeatherForecastController(ILogger<WeatherForecastController> logger) { _logger = logger; } [HttpGet] [EnableQuery] public IEnumerable<WeatherForecast> Get() { return Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = DateTime.Now.AddDays(index), TemperatureC = Random.Shared.Next(-20, 55), Summary = Summaries[Random.Shared.Next(Summaries.Length)], TestEnum = TestEnum.Test2 }) .ToArray(); } }
报错信息
{"Message":"The query specified in the URI is not valid. The string '1' is not a valid enumeration type constant.","ExceptionMessage":"The string '1' is not a valid enumeration type constant.","ExceptionType":"Microsoft.OData.ODataException","StackTrace":" at Microsoft.OData.UriParser.MetadataBindingUtils.ConvertToTypeIfNeeded(SingleValueNode source, IEdmTypeReference targetTypeReference)\r\n at Microsoft.OData.UriParser.BinaryOperatorBinder.PromoteOperandTypes(BinaryOperatorKind binaryOperatorKind, SingleValueNode& left, SingleValueNode& right, TypeFacetsPromotionRules facetsPromotionRules)\r\n at Microsoft.OData.UriParser.BinaryOperatorBinder.BindBinaryOperator(BinaryOperatorToken binaryOperatorToken)\r\n at Microsoft.OData.UriParser.MetadataBinder.Bind(QueryToken token)\r\n at Microsoft.OData.UriParser.FilterBinder.BindFilter(QueryToken filter)\r\n at Microsoft.OData.UriParser.ODataQueryOptionParser.ParseFilter()\r\n at Microsoft.AspNetCore.OData.Query.FilterQueryOption.get_FilterClause()\r\n at Microsoft.AspNetCore.OData.Query.Validator.FilterQueryValidator.Validate(FilterQueryOption filterQueryOption, ODataValidationSettings settings)\r\n at Microsoft.AspNetCore.OData.Query.Validator.ODataQueryValidator.Validate(ODataQueryOptions options, ODataValidationSettings validationSettings)\r\n at Microsoft.AspNetCore.OData.Query.EnableQueryAttribute.ValidateQuery(HttpRequest request, ODataQueryOptions queryOptions)\r\n at Microsoft.AspNetCore.OData.Query.EnableQueryAttribute.OnActionExecuting(ActionExecutingContext actionExecutingContext)"}
解决方案
要让OData支持直接使用枚举数值过滤,需要显式构建EDM模型并配置枚举的序列化规则,具体步骤如下:
- 添加EDM模型构建逻辑:创建方法生成包含枚举类型的EDM模型,设置枚举成员序列化方式为同时支持数值和名称。
- 修改OData服务配置:在
AddOData中使用自定义EDM模型,替换原简单配置。
修改后的启动代码
using Microsoft.AspNetCore.OData; using Microsoft.OData.Edm; using Microsoft.OData.ModelBuilder; var builder = WebApplication.CreateBuilder(args); // 构建EDM模型 static IEdmModel GetEdmModel() { var modelBuilder = new ODataConventionModelBuilder(); modelBuilder.EntitySet<WeatherForecast>("weatherforecast"); // 显式注册枚举类型,并配置序列化支持数值与名称 var enumType = modelBuilder.EnumType<TestEnum>(); enumType.ModelBuilder.EnumMemberSerialization = EnumMemberSerialization.ValueAndName; return modelBuilder.GetEdmModel(); } builder.Services.AddControllers().AddOData(opt => opt.Select().Filter().OrderBy() .AddRouteComponents("weatherforecast", GetEdmModel())); // 绑定自定义EDM模型 var app = builder.Build(); app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run();
验证
修改完成后,可使用以下两种方式过滤,均无需携带枚举命名空间:
- 使用枚举数值:
https://localhost:7282/weatherforecast?$filter=testEnum eq 1 - 使用枚举名称:
https://localhost:7282/weatherforecast?$filter=testEnum eq 'Test2'
两种方式均可正常返回过滤结果。
内容的提问来源于stack exchange,提问作者Paolo
相关产品推荐
相关产品推荐

