.NET 6 OData控制器Get方法路由多端点匹配歧义如何解决?
问题根源
这个多端点匹配报错是因为混用了普通ASP.NET Core特性路由规则和OData路由逻辑,默认路由系统扫描两个同名GET方法时,没有识别出路径参数的约束差异,把两个方法都注册成了同路径的匹配端点,请求进入时就会触发多匹配异常。
可行解决方案
方案1:使用OData原生路由约定(推荐,完全符合预期路径规范)
OData for .NET 6自带约定式路由规则,不需要手动给方法写冗余路由模板,按OData约定配置即可自动匹配你需要的两个路径,不会出现路由冲突,修改基类代码如下:
// 控制器路由保留/odata/[controller]格式,不需要加[action]占位符 [Route("/odata/[controller]")] public abstract class BaseController<T> : ODataController where T : class, DbModel { protected readonly ILogger<T> _logger; protected BaseController(ILogger<T> logger) { _logger = logger; } // 匹配 GET /odata/inheritedController 集合查询请求 [HttpGet] [EnableQuery] // 集合查询必须加该特性,否则OData查询参数不生效 public virtual IActionResult Get() { return Ok(_context.Set<T>().AsQueryable()); } // 匹配 GET /odata/inheritedController/{guid} 单实体查询请求 [EnableQuery] [HttpGet] // 不要手动写"{key:Guid}"路由模板,OData会自动识别名为key的参数绑定为主键路径,手动写模板反而会和内置路由规则冲突 public virtual async Task<SingleResult<T>> Get([FromODataUri] Guid key) { var result = _context.Set<T>().Where(p => p.Id == key); return SingleResult.Create(result); } }
同时在Program.cs配置OData服务时确认开启属性路由(默认是开启状态,不要手动关闭即可):
builder.Services.AddControllers() .AddOData(opt => opt .Select().Filter().OrderBy().Expand().Count().SetMaxTop(100) // 按业务需求开启OData查询功能 );
方案2:手动配置路由优先级(不依赖OData约定时使用)
如果要完全手动控制特性路由,需要给两个方法明确设置路由模板和匹配优先级,拉开两个端点的匹配顺序:
[Route("/odata/[controller]")] public abstract class BaseController<T> : ODataController where T : class, DbModel { protected readonly ILogger<T> _logger; protected BaseController(ILogger<T> logger) { _logger = logger; } // Order值越小优先级越高,优先匹配无参数的根路径请求 [HttpGet("", Order = 0)] [EnableQuery] public virtual IActionResult Get() { return Ok(_context.Set<T>().AsQueryable()); } // 仅当路径后携带Guid参数时才匹配该方法 [EnableQuery] [HttpGet("{key:Guid}", Order = 1)] public virtual async Task<SingleResult<T>> Get([FromODataUri] Guid key) { var result = _context.Set<T>().Where(p => p.Id == key); return SingleResult.Create(result); } }
方案3:Swagger兼容配置
如果修改路由后Swagger仍显示重复端点,只需要添加OData操作过滤器过滤掉非OData标准端点即可,不需要修改路由为[action]格式。
注意事项
- 你贴出的代码中构造函数命名为
AbstractBaseController,与类名BaseController不一致,会直接导致编译错误,需要修正为和类名一致。 - 不要为了规避冲突给路由加
[action]占位符,OData标准REST风格路径不需要携带Action名称,该配置会生成不符合预期的多余端点,也不符合OData路由规范。 - 若使用方案1,不要手动给单实体查询方法写路由模板,否则会和OData内置路由生成逻辑冲突,重复注册端点。
内容的提问来源于stack exchange,提问作者MaxWolodin
相关产品推荐
相关产品推荐

