Empty href after upgrading to asp.net core 2.2

Differences from earlier versions of routing explains what is happening here (emphasis mine):

The link generation ambient value invalidation algorithm behaves differently when used with endpoint routing.

Ambient value invalidation is the algorithm that decides which route values from the currently executing request (the ambient values) can be used in link generation operations. Conventional routing always invalidated extra route values when linking to a different action. Attribute routing didn't have this behavior prior to the release of ASP.NET Core 2.2. In earlier versions of ASP.NET Core, links to another action that use the same route parameter names resulted in link generation errors. In ASP.NET Core 2.2 or later, both forms of routing invalidate values when linking to another action.

...

Ambient values aren't reused when the linked destination is a different action or page.

In your example, lang is an ambient value and so it is not being reused when going from Home/Index to Home/About (different action). Without a value specified for lang, there is no matching action and so an empty href is generated. This is also described in the docs as an endpoint-routing difference:

However, endpoint routing produces an empty string if the action doesn't exist. Conceptually, endpoint routing doesn't assume that the endpoint exists if the action doesn't exist.

If you want to continue to use endpoint routing, it looks like you're going to need to pass the lang value from your controller into your view and then set it explicitly. Here's an example:

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>

You can make this a little less repetitive with e.g. an Action Filter, but the concepts are still the same. I can't see that there's another way to handle this (e.g. being able to mark a specific value as being ambient), but perhaps someone else will be able to chime in on that.


// Use the routing logic of ASP.NET Core 2.1 or earlier:
services.AddMvc(options => options.EnableEndpointRouting = false)
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);