Stiger
Stiger

Reputation: 1199

How to fix a 404 with routes in ASP.NET MVC?

I'm having a problem trying to get routing to work with ASP.NET MVC 3.0. I have the following routes declared:

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

    routes.MapRoute(
        "Default",
        "{controller}/{action}/{id}",
    new { controller = "Home", action = "RsvpForm", id = UrlParameter.Optional } 
    );

    routes.MapRoute(
        "TestRoute",
        "{id}",
        new { controller = "Product", action = "Index3", id = UrlParameter.Optional }
    );

    routes.MapRoute(
        "TestRoute2",
        "{action}",
        new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );
}

When I visit:

http://localhost

The site works correctly, and it appears to hit Default route.

When I visit:

http://localhost/1

I get a 404:

Server Error in '/' Application.

The resource cannot be found. Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.

Requested URL: /1

Here are the actions those routes correspond to:

public ActionResult Index3(int? id)
{
    Product myProduct = new Product
    {
        ProductID = 1,
        Name = "Product 1 - Index 3",
        Description = "A boat for one person",
        Category = "Watersports",
        Price = 275M
    };

    Product myProduct2 = new Product
    {
        ProductID = 2,
        Name = "Product 2 - Index 3",
        Description = "A boat for one person",
        Category = "Watersports",
        Price = 275M
    };

    ViewBag.ProcessingTime = DateTime.Now.ToShortTimeString();

    if (id == 1)
        return View("index", myProduct);
    else
        return View("index", myProduct2);
}

How do I structure my routes so that all three action methods are hit correctly?

Upvotes: 14

Views: 19265

Answers (5)

starlocke
starlocke

Reputation: 3661

In my case, the answer for the same problem was a matter of needing to "include in project" the relevant controllers and views instead of incorrect routing rules.

When mine were created, they weren't automatically included for some reason. This problem was revealed after I closed and re-opened the solution.

{+1 hate} awarded to Visual Studio for its faulty hyper-automation sending me digging through Web.Config files, trying to tack on extensions, and even trying (and failing) to whip up a decent ErrorController.

Upvotes: 0

Asuquo12
Asuquo12

Reputation: 835

Your routes MapRoute Default should be the last.

routes.MapRoute(
        "Default",
        "{controller}/{action}/{id}",
    new { controller = "Home", action = "RsvpForm", id = UrlParameter.Optional } 
    );

Upvotes: 2

George Stocker
George Stocker

Reputation: 57877

ASP.NET MVC Routing evaluates routes from top to bottom. So if two routes match, the first one it hits (the one closer to the 'top' of the RegisterRoutes method) will take precedence over the subsequent one.

With that in mind, you need to do two things to fix your problem:

  1. Your default route should be at the bottom.
  2. Your routes need to have constraints on them if they contain the same number of segments:

What's the difference between:

example.com/1

and

example.com/index

To the parser, they contain the same number of segments, and there's no differentiator, so it's going to hit the first route in the list that matches.

To fix that, you should make sure the routes that use ProductIds take constraints:

routes.MapRoute(
    "TestRoute",
    "{id}",
    new { controller = "Product", action = "Index3", id = UrlParameter.Optional },
    new { id = @"\d+" } //one or more digits only, no alphabetical characters
);

There are other issues with your set up, but those are two things that come to mind right off the bat.

Upvotes: 12

Bassam Mehanni
Bassam Mehanni

Reputation: 14944

Move your Default route to the end, Default route should be the last route to define because it acts as a catch all route

Upvotes: 0

Chandu
Chandu

Reputation: 82903

Push the most generic route to the last of the MapRoute call chain.

Try this:

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


        routes.MapRoute(
                "TestRoute",
                "{id}",
                new { controller = "Product", action = "Index3", id = UrlParameter.Optional }
        );

        routes.MapRoute(
                "Default", // Route name
                "{controller}/{action}/{id}", // URL with parameters
                new { controller = "Home", action = "RsvpForm", id = UrlParameter.Optional } // Parameter defaults
                //new { controller = "Product", action = "Index2", id = UrlParameter.Optional } // Parameter defaults
        );


        routes.MapRoute(
                "TestRoute2",
                "{action}",
                new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );

}

Upvotes: 0

Related Questions