Search code examples
c#asp.net-coreasp.net-mvc-routinghtml-helper

Html.ActionLink not aware of current area generates bad links


Context

I am migrating an ASP.NET MVC 5 app (running on .NET 4.7.2) to ASP.NET Core 2.2 on .NET 7.0. I am proceeding from a blank project and slowly moving-and-changing files. My current subject is the areas.

The Html.ActionLink() helper located in an area does not generate links for the current area. This was the previous behavior of the code. It now generates links for the default area.

Is this a configuration error or an approved change in the framework?

How can I fix the problem? Or change this behavior to ease the migration?

Code example

The page at /Manager in file Areas/Manager/Views/Home/Index.cshtml contains:

<p>@Html.ActionLink("Display everything", "Index", new { All = 1, })</p>

This is a link from the "Manager" area to the same area.

Expected URL: /Manager?All=1 or /Manager/Home?All=1 or /Manager/Home/Index?All=1 (same area)
Current URL: /?All=1 (default area)

The corresponding controller (Areas/Manager/Controllers/HomeController.cs):

public class HomeController : Controller
{
    public ActionResult Index(string All = null)
    {
         // ...
    }
}

The parent controller for the area (Areas/Manager/Controllers/Controller.cs):

[Area("Manager")]
public class Controller : BaseBackofficeController
{
    // ...

    public override Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { /* unrelated code */ }
}

The parent controller for the whole website (Shared/BaseBackofficeController.cs):

public abstract class BaseBackofficeController : Microsoft.AspNetCore.Mvc.Controller
{
    // ...unrelated code...
}

The route configuration in Startup.cs:

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(name: "default", pattern: "{controller=Home}/{action=Index}/{id?}");
    endpoints.MapAreaControllerRoute("Manager", "Manager", "Manager/{controller=Home}/{action=Index}/{id?}");
    // more unrelated routes
});

Things I tried

Adding [Area("Manager")] on the actual controller instead of the parent controller does not fix the issue.

@Html.ActionLink("Display everything", "Index", "Home", new { All = 1, })
=> `/?All=1

@Html.ActionLink("Display everything", "Index", "Home", new { All = 1, area = "Manager", })
=> /?All=1&area=Manager
It looks like the UrlHelper is not aware of the areas.


Solution

  • It looks like the UrlHelper is not aware of the areas.

    That is because the link matches the first route template.

    Change the order of your route template like below:

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapAreaControllerRoute("Manager", "Manager", "Manager/{controller=Home}/{action=Index}/{id?}");
    
        endpoints.MapControllerRoute(
            name: "default", 
            pattern: "{controller=Home}/{action=Index}/{id?}");
        // more unrelated routes
    });