Route never hits properly

62 Views Asked by At

I have this method in a controller named SecureAPI. The route looks pretty simple, but whatever I do I can't seem to invoke it.

Method:

[Route("SecureAPI/SetOrderAsProcessedAsync/{uid}")]
public async Task<IActionResult> SetOrderAsProcessedAsync([FromRoute(Name = "uid")] Guid uid)
{
    Order order = await _exp.Order(uid);
    _db.Update(order);

    order.IsProcessed = true;
    order.DateProcessed = DateTime.Now;

    await _db.SaveChangesAsync();

    return RedirectToActionPermanent("Orders", "Secure");
}

Link:

<a asp-controller="SecureAPI" asp-action="SetOrderAsProcessedAsync" asp-all-route-data="@(new { uid = Model.Order.UId }.ToRouteData())" class="btn-antan action flex-center-center"><icon awesome="Lock" />&nbsp;Set as processed</a>

Which generates this link:

http://localhost:5294/SecureAPI/SetOrderAsProcessedAsync?uid=f345f4d2-b184-4652-bd1b-78cc2f28aaff

ToRouteData extension:

public static IDictionary<string, string> ToRouteData(this object obj)
{
    IDictionary<string, string> result = new Dictionary<string, string>();

    foreach (IObjectPropertyModel prop in obj.GetProperties())
    {
        result.Add(prop.Name, prop.Value);
    }

    return result;
}

Any ideas? Thanks!

1

There are 1 best solutions below

4
Yong Shun On

The asp-all-route-data will interpret and flatten the dictionary data into the query string. Your route action expects to receive the uid as the route parameter.

Thus, the routes from the Controller action and the link generated from the anchor helper are not matched.

You have to use asp-route-{value} to interpret the value as a route parameter.

asp-route-uid="@Model.Order.UId"
<a asp-controller="SecureAPI" asp-action="SetOrderAsProcessedAsync" asp-route-uid="@Model.Order.UId" class="btn-antan action flex-center-center"><icon awesome="Lock" />&nbsp;Set as processed</a>

In the middleware pipeline, you need to specify the route constraint for your route: Controller = "SecureAPI", action = "SetOrderAsProcessedAsync" and place it before the default route constraint.

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(
        name: "SecureAPI",
        pattern: "SecureAPI/SetOrderAsProcessedAsync/{uid}",
        defaults: new { controller = "SecureAPI", action = "SetOrderAsProcessedAsync" });

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

enter image description here