ActionLink generates url parameters in instead of path parts

1.2k views Asked by At

I've got the following ActionMethod:

[Route("List/{listType}/{listID?}/{pageNumber?}/{pageSize?}/{output?}")]
public ActionResult List(int listType, int listID = 0, int pageNumber = 0, int pageSize = 10, string output = "html")
{
// Do Stuff
}

The first parameter is required, the rest is optional.

When I call the following default MVC method to create an ActionLink

@Html.ActionLink("MyLink", "List", "Message", new { listType = 4 }, null)

the link is generated to:

/Message/List?listType=4

I assumed it should be:

/Message/List/4

When I click the link, I receive a 404 error page, that the page is not found.

When I pass in the default value for the second parameter

@Html.ActionLink("MyLink", "List", "Message", new { listType = 4, listID = 0 }, null)

The link generated is correct:

/Message/List/4/0

However, when the value is optionally, I want to create the short link (/Message/List/4).

I've checked and double checked whether the naming of the parameter is correct, but this is not the problem...

I've also added a second List method

[Route("List/{listType})]
public ActionResult List(int listType)
{
// Do Stuff
}

The link with only 1 parameter is generated correctly, but when I pass in more parameters, they are generated like:

/Message/List/4?listID=5

Offcourse routes.MapMvcAttributeRoutes(); has been added to the RegisterRoutes function...

What problem do I not see which causes to generate an incorrect link when I only pass in 1 parameter?

3

There are 3 answers

0
Barry On

I've found a (possible) solution.

When I add the following to the RouteConfig, the links are generated correctly:

routes.MapRoute(
    name: "MessageList",
    url: "Message/List/{listType}",
    defaults: new { controller = "Message", action = "List", listType = 0 }
);

When only the listType is added as parameter the link is /message/list/4 and when I add more parameters, the link is also correct! The RouteAttribute on the ActionMethod is still there, so they work together now.

Not the solution I was hoping for, because I'd like to do it with a route attribute.

1
NightOwl888 On

I was only able to reproduce this problem with the following code:

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );

        routes.MapMvcAttributeRoutes();
    }
}

And fix it with this code:

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapMvcAttributeRoutes();

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    }
}

Routes are order sensitive and must be declared from most specific to least specific in order to work.

0
jfren484 On

You should try RouteLink instead of ActionLink. To use RouteLink you'd write something like this:

@Html.RouteLink("MyLink", new {
    controller = "Message",
    action = "List",
    listType = 4
})