升级到 asp.net core 2.2 后的空 href

Posted

技术标签:

【中文标题】升级到 asp.net core 2.2 后的空 href【英文标题】:Empty href after upgrading to asp.net core 2.2 【发布时间】:2019-05-08 19:18:57 【问题描述】:

我们已经构建了一个 ASP.NET Core 2.1 网站,其中 www.example.org/uk 和 www.example.org/de 等 URL 决定了要显示的 resx 文件和内容。升级到 ASP.NET Core 2.2 后,页面会加载,但生成的所有链接都会生成空白/空的 href。

例如,这样的链接:

<a asp-controller="Home" asp-action="Contact">@Res.ContactUs</a>

将在 2.2 中产生一个空的 href,如下所示:

<a href="">Contact us</a>

但是在 2.1 中我们得到了正确的 href:

<a href="/uk/contact">Contact us</a>

我们正在使用Constraint Map 来管理基于 URL 的语言功能 - 这是代码:

Startup.cs

// configure route options lang, e.g. /uk, /de, /es etc
services.Configure<RouteOptions>(options =>

    options.LowercaseUrls = true;
    options.AppendTrailingSlash = false;
    options.ConstraintMap.Add("lang", typeof(LanguageRouteConstraint));
 );

 ...

app.UseMvc(routes =>

    routes.MapRoute(
       name: "LocalizedDefault",
       template: "lang:lang/controller=Home/action=Index/id?");

LanguageRouteConstraint.cs

public class LanguageRouteConstraint : IRouteConstraint

    private readonly AppLanguages _languageSettings;

    public LanguageRouteConstraint(IHostingEnvironment hostingEnvironment)
    
        var builder = new ConfigurationBuilder()
            .SetBasePath(hostingEnvironment.ContentRootPath)
            .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);

        IConfigurationRoot configuration = builder.Build();

        _languageSettings = new AppLanguages();
        configuration.GetSection("AppLanguages").Bind(_languageSettings);
    

    public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection)
    
        if (!values.ContainsKey("lang"))
        
            return false;
        

        var lang = values["lang"].ToString();
        foreach (Language lang_in_app in _languageSettings.Dict.Values)
        
            if (lang == lang_in_app.Icc)
            
                return true;
            
        
        return false;
    

我缩小了问题范围,但找不到解决方法; 基本上在2.2。上述IRouteConstraint Match方法中有些参数没有设置,例如

httpContext = null
route = Microsoft.AspNetCore.Routing.NullRouter)

在 2.1 中

 httpContext = Microsoft.AspNetCore.Http.DefaultHttpContext
 route = lang:lang/controller=Home/action=Index/id?

我在 2.1 和 2.2 之间所做的唯一区别是我改变了

var builder = new ConfigurationBuilder()
   .SetBasePath(Directory.GetCurrentDirectory())
   .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);

以下(由于https://github.com/aspnet/AspNetCore/issues/4206)

 var builder = new ConfigurationBuilder()
    .SetBasePath(hostingEnvironment.ContentRootPath) // using IHostingEnvironment 
    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);

有什么想法吗?

更新 根据https://docs.microsoft.com/en-us/aspnet/core/fundamentals/routing?view=aspnetcore-2.2#parameter-transformer-reference ASP.NET Core 2.2 使用 EndpointRouting 而 2.1 使用 IRouter 基本逻辑。这解释了我的问题。现在,我的问题是 2.2 使用新的 EndpointRouting 的代码是什么样的?

【问题讨论】:

【参考方案1】:
// Use the routing logic of ASP.NET Core 2.1 or earlier:
services.AddMvc(options => options.EnableEndpointRouting = false)
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

【讨论】:

【参考方案2】:

Differences from earlier versions of routing 解释了这里发生的事情(强调我的):

链接生成环境值失效算法在与端点路由一起使用时表现不同。

环境值失效 是一种算法,它决定当前执行请求中的哪些路由值(环境值)可用于链接生成操作。当链接到不同的操作时,常规路由总是使额外的路由值无效。在 ASP.NET Core 2.2 发布之前,属性路由没有这种行为。在早期版本的 ASP.NET Core 中,指向使用相同路由参数名称的另一个操作的链接会导致链接生成错误。在 ASP.NET Core 2.2 或更高版本中,两种形式的路由在链接到另一个操作时都会使值无效。

...

当链接的目标是不同的操作或页面时,不会重复使用环境值。

在您的示例中,lang 是一个环境值,因此从Home/IndexHome/About(不同的操作)时它不会被重用。如果没有为 lang 指定值,则没有匹配的操作,因此会生成一个空的 href。这在文档中也被描述为端点路由差异:

但是,如果操作不存在,端点路由会生成一个空字符串。 从概念上讲,如果操作不存在,端点路由不会假定端点存在。

如果您想继续使用端点路由,您似乎需要将 lang 值从您的控制器传递到您的视图中,然后显式设置它。这是一个例子:

public class HomeController : Controller

    public IActionResult Index(string lang)
    
        ViewData["lang"] = lang; // Using ViewData just for demonstration purposes.
        return View();
    

<a asp-controller="Home" asp-action="Contact"
    asp-route-lang="@ViewData["lang"]">@Res.ContactUs</a>

您可以减少重复性,例如一个动作过滤器,但概念仍然相同。我看不出还有另一种方法可以处理这个问题(例如,能够将特定值标记为环境值),但也许其他人能够参与进来。

【讨论】:

您不必这样做,因为路线数据已经具有值asp-route-lang="@this.Context.GetRouteValue("lang")" 我很欣赏这个评论,也为迟到的回复道歉。总是必须传递 asp-route-whatever-ambient-value 或用(字符串 lang)装饰所有动作似乎需要做很多工作。有没有更简单的方法?我现在正在考虑升级到 ASP.NET Core 3.1,但必须使用 @ViewData 或 asp-route-ambient-value 更新 100 多个 URL 似乎是错误的设计方法。【参考方案3】:

您需要从路由数据中显式传递值:

@using Microsoft.AspNetCore.Routing;
<a ... asp-route-storeId="@this.Context.GetRouteValue("storeId")">Pay Button</a>

【讨论】:

抱歉回复晚了。总是必须通过 asp-route-whatever-ambient-value 似乎需要做很多工作。有没有更简单的方法?我现在正在考虑升级到 ASP.NET Core 3.1,但必须使用方案更新 100 多个 URL 似乎是错误的设计方法。

以上是关于升级到 asp.net core 2.2 后的空 href的主要内容,如果未能解决你的问题,请参考以下文章

HTTP 错误 502.5 - 升级到 ASP.NET Core 2.2 后 ANCM 进程外启动失败

不能将“Microsoft.AspNet.OData.Routing.ODataRoute”与端点路由一起使用。 ASP Net Core 2.2 的异常

Linq 查询在 ASP.NET-Core 3.0 及更高版本中对数字等字符串进行排序

从 ASP.NET Core 3.1 升级到 ASP.NET 5.0 后,User.Claims 为空

ASP.NET Core 2.2 MVC MapRoute 项目到 ASP.NET 3.0 端点 MapAreaControllerRoute “找不到此本地主机页面”

备忘ASP.NET MVC 5 升级到 ASP.NET Core MVC 的部分变化