0

My routing code is not working.

i am showing data in tabular format with sorting and pagination. my solution is working. when i hover mouse on column then url looks like http://localhost:55831/Customers?page=2&SortColumn=CompanyName&CurrentSort=ContactName

when i click on pagination numeric link then url looks like http://localhost:55831/Customers?page=3&SortColumn=ContactName

i want my url should look like 1) http://localhost:55831/Customers/2/CompanyName/ContactName 2) http://localhost:55831/Customers/3/ContactName

so i add one routing code. here it is

    routes.MapRoute(
        name: null,
        url: "Customers/{page}/{SortColumn}/{CurrentSort}",
        defaults: new
        {
            action = "Index",
            page = UrlParameter.Optional,
            SortColumn = UrlParameter.Optional,
            CurrentSort = UrlParameter.Optional
        }
    );

after adding the above routing code url looks bit weird. now url looks like

http://localhost:55831/Customers/1/CompanyName/CompanyName?controller=Customers
http://localhost:55831/Customers/2/CompanyName?controller=Customers

so when i click on above links then i am not redirecting to proper controller and action rather getting error.

so it means there is some problem in code which i added as routing in route.config.cs file.

so please help me to get my desired url what i mention above. thanks

EDIT

my full routing code

    routes.MapRoute(
        name: null,
        url: "{controller}/{action}/{page}/{SortColumn}/{CurrentSort}",
        defaults: new
        {
            action = "Index",
            page = UrlParameter.Optional,
            SortColumn = UrlParameter.Optional,
            CurrentSort = UrlParameter.Optional
        }
    );

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

    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );
Monojit Sarkar
  • 2,353
  • 8
  • 43
  • 94
  • Only the last parameter ca be marked `UrlParameter.Optional` –  Feb 02 '18 at 10:02
  • @StephenMuecke yes i did it what you said but still url looks like http://localhost:55831/Customers/2/CompanyName?controller=Customers and this links is not working. – Monojit Sarkar Feb 02 '18 at 10:06
  • Try adding `controller = "Customers"` in the defaults –  Feb 02 '18 at 10:07
  • @StephenMuecke should work. Reason for that is you didn't specify to which controller your route maps to by default and since routes map to controller/action, when url is generated by mvc, it automatically appends current controller to url. Since, there isn't a placeholder for "controller" parameter in target route, it is appended as querystring parameter – Talha5389 Feb 02 '18 at 10:11
  • @Talha5389 I change the routing code again but still not getting friendly url ` routes.MapRoute( name: null, url: "{controller}/{action}/{page}/{SortColumn}/{CurrentSort}", defaults: new { action = "Index", page = UrlParameter.Optional, SortColumn = UrlParameter.Optional, CurrentSort = UrlParameter.Optional } ); ` – Monojit Sarkar Feb 02 '18 at 10:12
  • @MonojitSarkar, how are you generating url for route? Try adding name to route, e.g. name: "CustomerSortRoute" and to generate url use `Url.RouteUrl("CustomerSortRoute",new {SortColumn = "CompanyName", page = 1})`. You might also have to add `action` and `controller` in routeValues while generating, if they aren't in defaults already – Talha5389 Feb 02 '18 at 10:16
  • you mean to say i am getting error because i have not mention name for routing? url is generating by `@Html.ActionLink and PagedListPager` – Monojit Sarkar Feb 02 '18 at 10:24
  • @MonojitSarkar, 1st route definition match anything with 1, 2, 3, 4 or 5 segments, and your 2nd and 3rd routes are pointless since they can never be reached (the first match wins). But your edit is confusing since its states _my full routing code_, yet it does not include the route in your first code snippet. –  Feb 02 '18 at 10:52
  • As many others have pointed out, there are several issues with your routing configuration. Routes need to be *constrained* in some way to keep them from overriding other valid route paths. See [Why map special routes first before common routes in asp.net mvc?](https://stackoverflow.com/a/35674633/) for an explanation and examples. – NightOwl888 Feb 02 '18 at 12:42

1 Answers1

2

This won't work because your routes have optional parameters which conflict with other routes.

For example take the url /MyController/MyAction/MyPage/213.

How would the routing be able to determine if you want: {controller}/{action}/{page}/{id} or {controller}/{action}/{page}/{SortColumn}/{CurrentSort}.

One solution might be to remove the optional parameters:

page = UrlParameter.Optional,
SortColumn = UrlParameter.Optional,
CurrentSort = UrlParameter.Optional

So your routes would look more like this:

routes.MapRoute(
    name: "PageWithSort",
    url: "{controller}/{action}/{page}/{SortColumn}/{CurrentSort}",
    defaults: new { action = "Index" }
);

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

However, here you are still going to get a conflict with PageWithId and the Default routes. So if you never use id in the Default routing then you might want to remove the optional parameter there. Or, if all routes with page always have an id then you could remove the optional parameter there. Alternatively, if page and id are truely optional you may consider removing the default route as PageWithId with the two optionals would handle both.

Side note: You should always name your routes as later it will allow you to do things like this:

@Html.RouteLink("Link Text", "RouteName", new { controller = "xxx" })

From your provided code you might consider changing

@Html.ActionLink("Company", "Index", new { page = ViewBag.CurrentPage, SortColumn = "CompanyName", CurrentSort = ViewBag.CurrentSort })

To

@Html.RouteLink("Company", "PageWithSort", new { controller = "Customers", action = "Index", page = ViewBag.CurrentPage, SortColumn = "CompanyName", CurrentSort = ViewBag.CurrentSort })
Ashley Medway
  • 7,151
  • 7
  • 49
  • 71
  • i have add your routing code but still url not become very friendly of links. so here is test project link https://github.com/karlosRivera/ASP.NET-MVC-EF-Sorting-Searching-and-Paging can you please run and test the code. it is test project and database is there in app_data folder. project size is very small. looking for your further help. – Monojit Sarkar Feb 02 '18 at 12:36
  • @MonojitSarkar I have added an example for the route link at the very end of my answer. – Ashley Medway Feb 02 '18 at 12:43
  • i can change `@Html.ActionLink to @Html.RouteLink` but i have used Pagelist for pagination which generate links where i have no control there to change their ActionLink to routeLink. so tell me what i can do? – Monojit Sarkar Feb 02 '18 at 13:10