Search code examples
c#asp.netasp.net-mvcasp.net-routingasp.net-core-tag-helpers

asp.net mvc Anchor Tag Helpers generates html "id" is part of the query string ,not part of the route data


Startup.cs

public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
    if (env.IsDevelopment()) {
        app.UseDeveloperExceptionPage();
     } else {
        app.UseExceptionHandler("/Home/Error");
     }
     app.UseStaticFiles();

     app.UseRouting();

     app.UseAuthentication();
     app.UseAuthorization();

     app.UseCookiePolicy(new CookiePolicyOptions {
         MinimumSameSitePolicy = SameSiteMode.Strict,
     });

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

CustomerController.cs

URL: /customer/details/7

[Authorize(Roles = "Admin")]
public async Task<IActionResult> Details(int id) {
    var model = GetUser();
    return View(model);
}

After adding the following code (get the detailed information of the currently logged in customer)

URL: /customer/details

[Route("[controller]/[action]")]
public async Task<IActionResult> Details() {
    int userId = Convert.ToInt32(HttpContext.User.Identity.Name);
    return await Details(userId);
}

Anchor Tag Helpers generates html "id" is part of the query string ,not part of the route data.

<a  asp-action="Details" asp-controller="Customer" asp-route-id="@HttpContextAccessor.HttpContext.User.Identity.Name">User Details</a>

It generates this HTML:

<a  href="/Customer/Details?id=1">User Details</a>

How to still generates HTML :

<a  href="/Customer/Details/1">User Details</a>

Thanks


Solution

  • Point 1: Your default routing template is

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

    Point 2: If you put a routing directly to your controller action this will override the default routing since your two action has the same name, you need to also add a routing to the other one. Check the below code, this is.

    SOLUTION 1

    [Authorize(Roles = "Admin")]
    [Route("[controller]/[action]/{id}")]
    public async Task<IActionResult> Details(int id) {
        var model = GetUser();
        return View(model);
    }
    

    [Route("[controller]/[action]")]
    public async Task<IActionResult> Details() {
        int userId = Convert.ToInt32(HttpContext.User.Identity.Name);
        return await Details(userId);
    }
    

    Point 3: If you can change the action name of the other controller then you can go with this approach. Just rename the action which has no routing directly on it.

    SOLUTION 2

    [Authorize(Roles = "Admin")]
    public async Task<IActionResult> Details2(int id) {
        var model = GetUser();
        return View(model);
    }
    

    [Route("[controller]/[action]")]
    public async Task<IActionResult> Details() {
        int userId = Convert.ToInt32(HttpContext.User.Identity.Name);
        return await Details(userId);
    }