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

.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模型并配置枚举的序列化规则,具体步骤如下:

  1. 添加EDM模型构建逻辑:创建方法生成包含枚举类型的EDM模型,设置枚举成员序列化方式为同时支持数值和名称。
  2. 修改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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 17:57:04