From the www:
...The routing engine will take the first route that matches the supplied URL and attempt to use the route values in that route. Therefore, less common or more specialized routes should be added to the table first, while more general routes should be added later on...
Why should I map specialized routes first? Someone can give me an example please where I can see the failing of "map common route first" ?
The reason why this happens is because the
RouteTable
is used like a switch-case statement. Picture the following:If
caseSwitch
is1
, the second block is never reached because the first block catches it.Route
classes follow a similar pattern (in both theGetRouteData
andGetVirtualPath
methods). They can return 2 states:VirtualPath
object in the case ofGetVirtualPath
). This indicates the route matched the request.null
. This indicates the route did not match the request.In the first case, MVC uses the route values that are produced by the route to lookup the
Action
method. In this case, theRouteTable
is not analyzed any further.In the second case, MVC will check the next
Route
in theRouteTable
to see if it matches with the request (the built in behavior matches the URL and constraints, but technically you can match anything in the HTTP request). And once again, that route can return a set ofRouteValues
ornull
depending on the result.If you try to use a switch-case statement as above, the program won't compile. However, if you configure a route that never returns
null
or returns aRouteValues
object in more cases than it should, the program will compile, but will misbehave.Misconfiguration Example
Here is the classic example that I frequently see posted on StackOverflow (or some variant of it):
In this example:
CustomRoute
will match any URL that is either 1, 2, or 3 segments in length (note thatsegment1
is required because it has no default value).Default
will match any URL that is 0, 1, 2, or 3 segments in length.Therefore, if the application is passed the URL
\Home\About
, theCustomRoute
will match, and supply the followingRouteValues
to MVC:segment1 = "Home"
controller = "MyController"
action = "About"
id = {}
This will make MVC look for an action named
About
on a controller namedMyControllerController
, which will fail if it doesn't exist. TheDefault
route is an unreachable execution path in this case because even though it will match a 2-segment URL, the framework will not give it the opportunity to because the first match wins.Fixing the Configuration
There are several options on how to proceed to fix the configuration. But all of them depend on the behavior that the first match wins and then routing won't look any further.
Option 1: Add one or more Literal Segments
Option 2: Add 1 or more RegEx Constraints
Option 3: Add 1 or more Custom Constraints
Option 4: Make Required Segments + Make the Number of Segments not Match Existing Routes
In the above case, the
CustomRoute
will only match a URL with 4 segments (note these can be any values). TheDefault
route as before only matches URLs with 0, 1, 2, or 3 segments. Therefore there is no unreachable execution path.Option 5: Implement RouteBase (or Route) for Custom Behavior
Anything that routing doesn't support out of the box (such as matching on a specific domain or subdomain) can be done by implementing your own
RouteBase
subclass or Route subclass. It is also the best way to understand how/why routing works the way it does.This class was borrowed from: Is it possible to make an ASP.NET MVC route based on a subdomain?