ASP.NET Core Web API MapControllerRoute配置models路由返回404问题排查
问题原因
你遇到的404问题核心是OData路由优先级高于普通MVC常规路由,触发了路由抢占,具体原因如下:
- 你在EdmModel中注册了名为
Models的实体集,而ModelsController继承自ODataController,OData路由系统会优先匹配和实体集同名的/models路径 - OData匹配
/models路径时,会查找符合OData约定的Get方法,你原本符合约定的Get()方法已经被注释,实际存在的GetModels()不符合OData默认的方法名匹配规则,OData匹配失败后直接返回404,不会继续向下匹配你后续注册的MapControllerRoute自定义路由 - 而
Projects对应的实体没有在EdmModel中注册,OData不会抢占/projects路径,请求可以正常匹配到后续的自定义路由,所以访问正常
解决方案
可以根据你的业务需求任选以下一种方案解决:
方案1:调整路由注册顺序(最便捷)
路由匹配遵循先注册先匹配的规则,你可以把所有自定义的MapControllerRoute注册逻辑移到endpoints.MapControllers();之前,让自定义路由优先匹配:
app.UseEndpoints(endpoints => { // 先注册自定义常规路由,优先匹配 endpoints.MapControllerRoute( name: "test", pattern: "test/data", defaults: new { controller = "Models", action = "addsampledata" } ); endpoints.MapControllerRoute( name: "projects", pattern: "projects/create", defaults: new { controller = "Projects", action = "createproject" } ); endpoints.MapControllerRoute( name: "projects", pattern: "projects", defaults: new { controller = "Projects", action = "getprojects" } ); endpoints.MapControllerRoute( name: "models", pattern: "models", defaults: new { controller = "Models", action = "getmodels" } ); endpoints.MapControllerRoute( name: "models", pattern: "models/create", defaults: new { controller = "Models", action = "createmodel" } ); endpoints.MapControllerRoute( name: "models", pattern: "models/retrieve/{model}", defaults: new { controller = "Models", action = "retrievemodels" } ); // 最后注册控制器路由(包含OData路由) endpoints.MapControllers(); });
方案2:修改OData实体集名称,避免路由冲突
修改EdmModel中注册的实体集名称,不要和自定义路由的/models路径重名:
private static IEdmModel GetEdmModel() { var builder = new ODataConventionModelBuilder(); // 把实体集名称从Models改成其他值,比如ODataModels builder.EntitySet<Model>("ODataModels").EntityType.HasMany(m => m.SubModels); builder.EntitySet<Property>("Propterties"); return builder.GetEdmModel(); }
方案3:适配OData路由规则
如果你希望/models路径走OData路由,直接取消ModelsController中注释的Get()方法即可,或者给GetModels()方法加上OData路由特性匹配规则。
内容的提问来源于stack exchange,提问作者Florent
相关产品推荐
相关产品推荐

