MVC Core结合Api版本控制时,~覆盖路由前缀致Url.RouteUrl失效
解决ASP.NET Core + aspnet-api-versioning中
~覆盖路由导致Url.RouteUrl返回null的问题 这个坑我之前踩过!核心原因是用~定义的路由会完全脱离控制器的路由前缀,变成一个独立的路由条目,而Url.RouteUrl在生成URL时,没办法自动关联到API版本参数,也找不到匹配的完整路由规则,所以直接返回null。下面给你几个实用的解决方案:
方案1:给独立路由指定名称,传递完整路由参数
首先给你的GetBooksByAuthor方法的路由加上明确的名称,然后调用Url.RouteUrl时,必须传递所有必要的路由参数(包括API版本):
修改控制器代码:
[Route("v{api-version:apiVersion}/[controller]")] [ApiVersion("1.0")] // 务必给控制器标记对应的API版本,确保路由解析时能关联版本 public class BooksController : ApiController { [HttpGet] [Route("{bookId}", Name = "GetBook")] public Book GetBook(int bookId) { } // 给这个独立路由添加唯一名称,保留API版本参数 [HttpGet] [Route("~/v{api-version:apiVersion}/authors/{authorId:int}/books", Name = "GetBooksByAuthor")] public IEnumerable<Book> GetBooksByAuthor(int authorId) { } }
生成URL时的代码:
// 获取当前请求的API版本,或者手动指定版本号 var apiVersion = HttpContext.GetRequestedApiVersion()?.ToString() ?? "1.0"; // 必须传递所有路由参数:api-version和authorId,参数名要和路由定义完全一致 var bookUrl = Url.RouteUrl( "GetBooksByAuthor", new { api_version = apiVersion, authorId = 1 } );
方案2:使用LinkGenerator替代Url.RouteUrl(推荐)
ASP.NET Core 3.0及以上版本提供的LinkGenerator服务,比Url.RouteUrl更灵活,能更好地处理这种脱离控制器前缀的独立路由:
注入LinkGenerator:
private readonly LinkGenerator _linkGenerator; public BooksController(LinkGenerator linkGenerator) { _linkGenerator = linkGenerator; }
生成URL:
var apiVersion = HttpContext.GetRequestedApiVersion()?.ToString() ?? "1.0"; var bookUrl = _linkGenerator.GetPathByRouteValues( HttpContext, routeName: "GetBooksByAuthor", values: new { api_version = apiVersion, authorId = 1 } );
LinkGenerator会更精准地匹配路由规则,尤其是处理这种独立路由时,可靠性比Url.RouteUrl高很多。
方案3:避免使用~,改用路由约束组合
如果业务允许,你也可以不用~覆盖前缀,而是调整控制器路由和方法路由的组合来实现需求,这样能让路由继承关系更清晰:
[Route("v{api-version:apiVersion}")] [ApiVersion("1.0")] public class BooksController : ApiController { // 路由:v1/books/{bookId} [HttpGet("books/{bookId}", Name = "GetBook")] public Book GetBook(int bookId) { } // 路由:v1/authors/{authorId}/books [HttpGet("authors/{authorId:int}/books", Name = "GetBooksByAuthor")] public IEnumerable<Book> GetBooksByAuthor(int authorId) { } }
这种方式下,所有方法路由都继承控制器的v{api-version}前缀,Url.RouteUrl就能自动识别API版本参数,不会出现返回null的问题。
内容的提问来源于stack exchange,提问作者MonkeyWrench
相关产品推荐
相关产品推荐

