1

I see a lot of problems with MVC routes and I'm having a similar problem getting a route to match a URL.

routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

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

routes.MapRoute("Beer", "Beer/{beerid}", new { controller = "Beer", action = "Id", beerid = 0});

routes.MapRoute("Beer", "Beer/{beername}", new { controller = "Beer", action = "Name" });

BeerController Methods

public ActionResult Id(int beerid)
public ActionResult Name(string beername)

If I change the methods to the following,

public ActionResult Id(int? id)    
public ActionResult Name(string id)

the default routing works with the following URLs:

http://localhost/Beer/Id/100
http://localhost/Beer/Name/Coors

But what I'm going for is just

http://localhost/Beer/100
http://localhost/Beer/Coors

Any ideas?

asymptoticFault
  • 4,491
  • 2
  • 19
  • 24
Jay
  • 43
  • 1
  • 5

1 Answers1

3

So a couple things here.

  1. More specific routes should be placed before more general routes, because the first route that is matched will be used and routes are inspected in the order they are added.

  2. If you plan on not providing the name of the action in your URL then you will need to do something to ensure the correct route is targeted so the correct default value will be used. In your case you could use a route constraint to distinguish between the two. Try changing your beer id route to this:

    routes.MapRoute(
        name: "Beer",
        url: "Beer/{beerid}",
        defaults: new { controller = "Beer", action = "Id", beerid = 0},
        constraints: new { beerid = @"\d+" }
    );
    

    The constraint will ensure that the route only matches two-segment URLs where the second segment is composed of one or more digits. This route as well as your route for beer name should be placed before the default route.

UPDATE

My configuration seems to be yielding the results you want. The entirety of my RegisterRoutes method is as follows:

routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

routes.MapRoute(
    name: "Id",
    url: "Beer/{beerid}",
    defaults: new { controller = "Beer", action = "Id", beerid = 0 },
    constraints: new { beerid = @"\d+" }
);

routes.MapRoute(
    name: "Name",
    url: "Beer/{beername}",
    defaults: new { controller = "Beer", action = "Name" }
);

routes.MapRoute(
    name: "Default",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
asymptoticFault
  • 4,491
  • 2
  • 19
  • 24
  • I just tried that - it's still not routing.. getting a Resource can't be found: Requested URL: /Beers/110 The Id action method is not being hit.. I tried creating a new action method called BeerById and using that to avoid confusion with Id method.. it's just not picking up the routing rule.. the Global.asax.cs breakpoints don't hit either – Jay Sep 26 '13 at 17:59
  • @Jay You should request */Beer/110* not **Beers**. Your route is set to match `Beer` exactly. – asymptoticFault Sep 26 '13 at 18:01
  • @Jay It seems to work fine for me. Also the route name needs to be unique, you can't have two called "Beer". I changed the id one to "Id" and the name one to "Name". – asymptoticFault Sep 26 '13 at 18:15