Antrim Antrim - 3 months ago 7
ASP.NET (C#) Question

Can't route to both "{controller}/{action}/{id}" and "{controller}/{id}"

In my MVC website, I'd like to have my routes set up like this:


  • site.com/Customer
    - where you can select a customer.

  • site.com/Customer/123
    - where you can see the information for the selected customer.



So basically, having just one view that depending on if you have an
{id}
shows different stuff.

So I add the mapped route
DefaultNoAction
in
RouteConfig.cs
:

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

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

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


And the following in the controller:

public ActionResult Index(int? id)
{
return View(id);
}


and the view:

@model int?

...

$(function () {
var customerId = @Model;
...
}


Now:


  • If I try accessing
    site.com/Customer/123
    I'll get a 404.

  • If I go to
    site.com/Customer
    the
    @Model
    is not set to anything, so when I reference it in my jQuery it throws a syntax error because it'll see
    var customerId = ;



Obviously I'm not approaching this the right way or there's a better way to do what I'm trying to do. Any direction?

Answer

The order of your routes matter (the routing engine will stop searching when it finds the first match). ../Customer/123 matches you Default route (it contains 2 segments) and you get a 404 because there is no method named 123 in your CustomerController. You need to move the DefaultNoAction route before the Default route.

However this may cause other issues with your routing and you should make the DefaultNoAction route unique if you also want to use the Default route

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

As for the javascript error, assuming you want the value of customerId to be null if the methods id parameter is null, then you can use

var customerId = @Html.Raw(Json..Encode(Model));
console.log(customerId); // returns null if the model is null

As a side note, your Parameters2 route will not work correctly either. Only the last parameter can be marked as Url.Optional, and if only one or the 2 parameters were provided it would match the Default route.