Search code examples
c#asp.net-coreasp.net-core-mvcasp.net-core-routing

Mvc Route 404 When Passing in id through URL


let me start with explaining what I am trying to do. I have a form with a drop down where on the change of the value triggers a label text to change. To do this I attached a onchange script event to fire off.

 <select onchange="ChangeLabel()" id="ContainerValue" asp-for="Container" class="form-control"/>

The Label

<label id="AddressLabel" asp-for="Container" class="control-label"/>

The script it calls is

 <script>
    function ChangeLabel() {
        var val = $('#ContainerValue').val();
        $.ajax({
            url: '/Rundown/GetLabel/' + val ,
            type: "GET",
            dataType: "text",
            success: function (labelText) {
                $("#AddressLabel").html(labelText);
            }
        });
    }
</script>

So I create a action in my controller called GetLabel with a parameter id.

[HttpGet]
// GET: Rundown/GetLabel/5
public string GetLabel(int id)
{
    return "x";
}

So I am pretty sure I am using default routing that's created on setup of project. As far as I know I didn't mess with this.

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

    app.UseStaticFiles();

    app.UseAuthentication();

    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}

Now when I change the selection in the drop down the change request gets fired of and a request is made to /Rundown/GetLabel/1 but it returns a 404 error. Just for testing purposes I noticed that if I did /Rundown/GetLabel/?id=1 I would hit my GetLabel action and would get back my "x" string value. Any idea why I am not seeing my action get hit with the normal [controller]/[action]/[id] routing I would of expected to work?

The only other related information I can think of is a route in a fixture above the controller class.

[Route("[controller]/[action]")]
public class RundownController : Controller

Solution

  • You are mixing attribute and convention-based routes which is causing a conflict.

    The attribute route will take priority here over the convention-based route and since you do not have a route template for the action parameter it is not being found.

    Add a route template for the action

    Route("[controller]/[action]")]
    public class RundownController : Controller {
    
        // GET: Rundown/GetLabel/5
        [HttpGet("{id}")]        
        public string GetLabel(int id) {
            return "x";
        }
    
    }
    

    Having the attribute route on the controller and just the HttpGet on the action meant that the URL would have looked like

    Rundown/GetLabel?id=5
    

    By including the route template parameter [HttpGet("{id}")] you get the desired behavior.

    An alternative is to remove the Route("[controller]/[action]")] from the top of the controller and allow the default routing definition from the startup MapRoute

    Reference Routing to controller actions in ASP.NET Core