升级OData 8.2.3后自定义Query参数接口失效问题排查
问题分析与解决方案
问题根源
你关闭了OData的属性路由(EnableAttributeRouting = false),同时自定义接口使用了MVC的[Route]特性。在OData 8.x版本中,禁用属性路由时会启用传统约定式路由,此时你的自定义接口路径api/v1/department/getDepartmentsByCompany会被OData路由解析器错误识别为:尝试获取Department实体的key值为getDepartmentsByCompany(而该实体的key是int类型),因此抛出类型不匹配的错误。
解决方案
1. 启用OData属性路由
修改Program.cs中的OData配置,将EnableAttributeRouting设为true(OData 8.x推荐使用属性路由,可正确识别MVC的[Route]特性):
builder.Services.AddControllers(g => { g.EnableEndpointRouting = false; }).AddOData(opt => { var batchHandler = new DefaultODataBatchHandler(); opt.AddRouteComponents("api/v1", DIRegister.GetEdmModels(), batchHandler); opt.Count().Select().Filter().OrderBy().Expand().SetMaxTop(int.MaxValue); opt.EnableQueryFeatures(int.MaxValue); // 启用属性路由,让自定义Route特性生效 opt.EnableAttributeRouting = true; }).AddJsonOptions(g => { g.AllowInputFormatterExceptionMessages = true; });
2. 排除OData路由处理(可选)
如果需要让自定义接口完全脱离OData路由的拦截,可以给接口添加[NonODataRoute]特性(OData 8.0+提供):
[HttpGet, Route("api/v1/department/getDepartmentsByCompany")] [Microsoft.AspNetCore.OData.Query.EnableQuery] [NonODataRoute] // 标记该接口不被OData路由处理 public Task<BaseResponse<IEnumerable<Department>>> GetDepartmentByCompany([FromQuery] int id, [FromQuery] FunctionalType? functionalType) { try { return Task.FromResult(new BaseResponse<IEnumerable<Department>> { Data = /* 业务数据 */ }); } catch (Exception ex) { LogHelper.LogException(ex, _hostingEnvironment); return Task.FromResult(new BaseResponse<IEnumerable<Department>> { Success = false, Message = "Failed" }); } }
3. 注册为OData函数(可选)
如果希望自定义接口支持OData查询能力并作为OData函数暴露,需在Edm模型中注册对应函数:
// 在DIRegister.GetEdmModels()中添加函数配置 var builder = new ODataConventionModelBuilder(); builder.EntitySet<Department>("Department"); // 注册集合函数 var getDepartmentsFunc = builder.EntityType<Department>().Collection .Function("getDepartmentsByCompany") .ReturnsCollection<Department>(); getDepartmentsFunc.Parameter<int>("id"); getDepartmentsFunc.Parameter<FunctionalType?>("functionalType"); return builder.GetEdmModel();
同时修改控制器接口的路由特性为OData专用:
[HttpGet] [ODataRoute("getDepartmentsByCompany")] [EnableQuery] public Task<IEnumerable<Department>> GetDepartmentByCompany([FromODataUri] int id, [FromODataUri] FunctionalType? functionalType) { // 业务逻辑实现 }
内容的提问来源于stack exchange,提问作者Gopi
相关产品推荐
相关产品推荐

