OData路由结合API版本控制时出现重复路由模板运行时异常
看起来你遇到的问题是因为控制器手动配置的路由和Asp.Versioning的OData路由组件配置重复叠加导致的,从异常信息里能看到v2的Get方法路由模板变成了odata/v{version:apiVersion}/Parts/odata/v{version:apiVersion}/Parts,明显是两次路由配置拼接的结果。下面是具体的解决步骤:
1. 移除控制器上的[Route]属性
你现在在v1和v2的PartsController上都加了[Route("odata/v{version:apiVersion}/[controller]")],但Asp.Versioning的OData集成会自动根据你配置的路由前缀生成对应路由,手动添加这个属性会和OData的路由配置冲突,导致重复拼接。
修改后的v1控制器示例:
namespace ...Api.Versions.v1.Controllers { [ApiController] [ApiExplorerSettings(GroupName = "v1")] [ApiVersion("1")] // 移除手动的[Route]属性 public class PartsController : ODataController { [Produces("application/json")] [EnableQuery] [HttpGet] public async Task<IQueryable<Part>> Get() { ... } } }
v2的PartsController做同样的修改即可。
2. 调整API版本控制的OData配置
确保AddApiVersioning中的OData路由组件配置正确,同时避免和AddControllers中的OData配置重复冲突:
修改后的ConfigureServices示例:
public void ConfigureServices(IServiceCollection services) { ... // 基础控制器配置,只保留OData的通用查询特性 services.AddControllers() .AddOData(options => { options.EnableQueryFeatures(maxTopValue: 8000); options.TimeZone = TimeZoneInfo.Utc; }); services.AddApiVersioning(options => { options.AssumeDefaultVersionWhenUnspecified = true; options.DefaultApiVersion = new ApiVersion(1); options.ReportApiVersions = true; options.ApiVersionReader = new UrlSegmentApiVersionReader(); }) .AddMvc() .AddOData(options => { // 这里只配置OData路由组件前缀,由版本控制自动填充版本号 options.AddRouteComponents("odata/v{version:apiVersion}"); }) .AddODataApiExplorer(options => { options.GroupNameFormat = "'v'V"; options.SubstituteApiVersionInUrl = true; }); ... }
3. 验证模型配置
你的PartModelConfiguration已经正确实现了IModelConfiguration接口,Asp.Versioning会自动发现并注册它,这部分不需要修改。后续如果v1和v2的模型有差异,直接在ConfigureV1和ConfigureV2方法中调整即可。
为什么这样能解决问题?
Asp.Versioning的OData集成会自动为每个版本的控制器生成匹配odata/v{version:apiVersion}/[controller]格式的路由,如果你手动在控制器上加[Route]属性,就会导致路由模板被重复拼接,最终触发“相同名称的路由必须有相同模板”的运行时异常。移除手动路由配置后,由版本控制组件统一管理路由生成,就能避免这个问题。
备注:内容来源于stack exchange,提问作者Jack Cotterill

