Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setting up ASP.Net MVC 4 Routing with custom segment variables

I just began working on an application with a couple areas (basic grid master / details type system..) I'm looking into taking advantage of the nice routing features in MVC (4 specifically) and I'm "just not getting it" I presume.

Currently the only route defined is the basic one:

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

which is fine, it works with the areas we have defined, so I'm assuming it must know where the user is and route to the appropriate controller based contextually on the location / area that the user is in.. so far nice..

Now, i'm trying to set up a new route that can handle

/someController/someAction/{statusName} 

and specifically something like:

/OrderManager/List/New 

AND

/OrderManager/List/Viewed

where "New" is the "New" status and have the Action Signature look like:

public ActionResult List(string statusName)

i was assuming I could just add the new route below the default one identifying "statusName" instead of Id, but of course, how the H would the routing mechanism know the difference between :

/controller1/action1/15

/controller2/action2/new

I did try adding a "static" route in the form of

routes.MapRoute("Default", 
            "ControllerName/ControllerAction/{statusName}", 
            new { statusName = UrlParameter.Optional }
        );

I thought I could "hiJack" just that one route and do something special with it, but to know avail, the router stops at first match?? I'm assuming that was the wrong way to address this issue anyhow..

so now I'm going through the idea of getting to something like:

/somecustomroutename/somesortValue

ex. /OrderManagerList/viewNew

where these routes would basically be "aliases". I had thought that adding the following route would do the trick:

 routes.MapRoute("Default_List",
          "OrderManagerList/{statusName}",
          new {controller="OrderManager", action="List", statusName= UrlParameter.Optional }
      );

with the associated action on the OrderManager controller:

public ActionResult List(string statusName)

no matter what I try, the argument is null, or the "resource cannot be found"

I know the controllers need to have a corresponding View file.. but that's not the issue here, the issue is my attempt at understanding the routing..

SO my questions.. fundamentally, what am I missing about the routing in MVC (4)? even some good articles for a simpleton like myself to understand?

my understanding; define a route, and map it's "endpoint".. however, i think i'm not understanding the assumptions that the machine is making..

anyhow, let me know if further explain / edit is required..

thanks in advance.

like image 526
hanzolo Avatar asked Dec 27 '22 10:12

hanzolo


1 Answers

The basic principle of routes is that they are evaluated from the top down, and the routing systems uses the first match, not the best match.

The implication of this is that you must order your routes in order of specificity, with the most specific route first and the most general route last.

With this principle in mind, let’s look at your situation. Initially, you have only the default route defined:

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

The URL pattern is "{controller}/{action}/{id}". By itself, this would match any three-segment URL, and would not match any URL that had less than three segments. However, the third input parameter is the default parameter, which defines defaults for the first and second segment and indicates that the third segment is optional. The next effect of this is to make the route match URL having 0,1, 2 or 3 segments.

Now you want to add a route where the third URL segment is mapped to a “statusName” parameter, and can handle URLs like:

OrderManager/List/New 
OrderManager/List/Viewed 

There are two basic approaches you can take here. You can 1) create a very specific route that will handle these two URLs only, or 2) you can try and create a more general route to handle the general case. Let’s look at the first case first. You can create a route as follows:

routes.MapRoute("", "OrderManager/List/{statusName}",
              new { Controller = "OrderManager", Action = "List" });

Note that because this route is more specific than the default route, you must put this route before the default route.

If you want to have a more general route, you need to decide how this route will differ from the default route, since they both will match URLs having three segments. Let’s say you decide that the new route will accept anything that only contains letters in the third segment, leaving the default route to handle anything containing numbers. You can do this using route constraints. For example you could write a route as follows:

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
            constraints: new { id = @"^\d+$" });

        routes.MapRoute(
            name: "NewRoute",
            url: "{controller}/{action}/{statusName}",
            defaults: new { Controller = "OrderManager", Action = "List" },
            constraints: new { statusName = "^[A-Za-z]+$" });

With these two routes, any three-segment URL having only letters in the third segment will put the third segment into a variable called “statusName”, whereas any URL with an integer in the third segment will put the third segment into a variable called “id”.

In any applications of real complexity, routes can get complicated, and it is very advantageous to write unit tests for your routes, to insure that you don’t screw things up when you add or modify a route.

For good references on routing, see Scott Sanderson's book or see the MSDN documentation

like image 140
Joe Alfano Avatar answered Jan 12 '23 01:01

Joe Alfano