我们正在将 ASP.NET Core 2.2 项目升级到使用 EndPoint 路由的 ASP.NET 3.0。
我们有大量Url.RouteUrl使用命名路由构建的 url 列表,例如:
string url = Url.RouteUrl("blog-details", new { title = item.Title, id = item.Id });
// returns correct link of https://example.org/us/blog/some-title-6 in 2.2 but is blank in 3.0
[Route("~/{lang}/blog/{title}-{id}", Name= "blog-details")]
public async Task<IActionResult> Details(string title, int id)
{
}
Run Code Online (Sandbox Code Playgroud)
升级到 3.0 后,这些 url 只会产生一个空白的 href。我们startup.cs看起来像这样:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddControllersWithViews(options =>
{
options.Filters.Add(new MiddlewareFilterAttribute(typeof(LocalizationPipeline)));
})
.AddViewLocalization(LanguageViewLocationExpanderFormat.SubFolder)
.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix);
services.AddRazorPages();
...
}
Run Code Online (Sandbox Code Playgroud)
我们尝试用下面的替换,但这会创建错误的链接并且不允许我们作为变量重用,例如:
<a asp-action="Details" asp-controller="Blog" asp-route-title="item.Title" asp-route-id="@item.Id">Link here</a>
url = Url.Action("Details", "Blog", new { id = item.Id, title = item.Title });
url = Url.RouteUrl(new { action = "Details", controller = "Blog", id = item.Id, title = item.Title });
// all returns https://example.org/us/blog/details/6?title=some-title
<a asp-controller="Home" asp-action="Pricing">Pricing</a>
// returns https://example.org/us/home/pricing instead of correct https://example.org/us/pricing
[Route("~/{lang}/pricing")]
public async Task<IActionResult> Pricing()
{
...
}
Run Code Online (Sandbox Code Playgroud)
但是,这有效:
<a asp-controller="Signup" asp-action="Customer">Sign up</a>
// returns correct https://example.org/us/signup/customer
[Route("~/{lang}/signup/customer")]
public IActionResult Customer()
{
...
}
Run Code Online (Sandbox Code Playgroud)
如果我们想使用 EndPoint 路由(而不是旧的 2.2.-way),我们做错了什么?
有两个项目负责这种行为。
首先,让我们看看路由是如何生成的:
[Route("~/{lang}/pricing")]
Run Code Online (Sandbox Code Playgroud)
该{lang}令牌是有问题的。人们会期望在从一个页面浏览到另一个页面时——就像在 ASP.Net Core 2.2 下的情况一样——这个值将被保留和重用。现在已经不是这样了。该文档使用id示例证明了它的合理性:book id 123不应导致login user id 123. 不幸的是,这同样适用于更稳定的语言代码lang。
因此,URL 生成必须包含lang代码。使用问题中的第一个 URL,它将变为:
string url = Url.RouteUrl("blog-details", new {lang="en", title = item.Title, id = item.Id });
[Route("~/{lang}/blog/{title}-{id}", Name= "blog-details")]
Run Code Online (Sandbox Code Playgroud)
第二项是默认路由。由于您的路由由于缺少lang参数而未匹配,因此使用默认路由。由于您使用了不属于默认路由模板的参数,因此将它们添加到 URL ( ?title=some-title)的末尾。如果没有默认路由,则根本不会生成 URL。
有一篇关于这个问题的有趣帖子值得一读。
对于所有读者来说,旁注是,可以提取应该回收的环境值并将其插入链接代:
@{string lang = (string)ViewContext.RouteData.Values["lang"]; }
<a asp-area="" asp-controller="myController" asp-action="myAction" asp-route-lang=@lang >click here</a>
Run Code Online (Sandbox Code Playgroud)