ASP.Net MVC routing action name conflicts - asp.net-mvc

We have a website that deals with artists and venues and we're developing it in ASP.net MVC.
We have our artist views in a folder (Views/Artists/..), an ArtistsController, ArtistsRepository and adhere to the REST action names such as Show, New, Delete etc.
When we first mocked up the site, everything worked well in our test environment as our test URLs were /artists/Show/1209
but we need to change this so the website appears as /artists/Madonna and /artists/Foo-Fighters etc
However, how can we distinguish between valid artist names and the names of the actions for that controller?! For example, artists/PostComment or artists/DeleteComment? I need to allow the routing to handle this. Our default Show route is:
routes.MapRoute(
"ArtistDefault",
"artists/{artistName}",
new { controller = "Artists", action = "Show", artistName = ""}
One way around this is for our website to visibly run on /artists, but have our controller renamed to the singular - ArtistController - as opposed to ArtistsController. That would go against the naming conventions we went with when we started (but hey!).
Do you have any other recommendations? If possible we could also route depending on the verbs (so PostComment would be a POST so we could perhaps route to that action), but I'm not sure if that is advisable let alone possible.
Thanks

The 4th parameter to MapRoute allows you to specify restrictions for values. You can add a route before this one that is for "artists/{action}/{id}" with a restriction on the valid values for action; failing to match one of your actions, it'll fall through to the next route which will match for artist name.

You would actually define multiple routes... the defined actions in your controller would go first with the default being at the bottom. I like to think of route definitions as a "big 'ole switch statement" where first rule satisfied wins..
routes.MapRoute(
"ArtistPostComment",
"artists/PostComment/{id}",
new { controller = "Artists", action = "PostComment", id = "" }
);
routes.MapRoute(
"ArtistDeleteComment",
"artists/DeleteComment/{id}",
new { controller = "Artists", action = "DeleteComment", id = "" }
);
routes.MapRoute(
"ArtistDefault",
"artists/{artistName}",
new { controller = "Artists", action = "Show", artistName = "" }
);

Related

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.
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

MVC hides virtual directories in IIS

I have the default directory in my IIS server set as an MVC 4 Razor application. I have it set up so that dynamic actions can be passed into the url. For example.
www.mydomain.com/4
www.mydomain.com/5
Basically those two launch accounts for users with id's of 4 and 5 respectively.
Works great.
But, I have a virtual directory on the same server called admin. I would hope that I could navigate to www.mydomain.com/admin but sadly MVC intercepts it and thinks that i'm looking up the user id of amdin.
Is there a way to poke holes in the route to allow for virtual directories?
Thanks in advance!
/Eric
########## adding my route
//route for site root
routes.MapRoute(
"YourRouteName", // Route name
"{flightNumber}/{action}", // URL with parameters
new { controller = "Home", action = "Index", flightNumber = " " } // Parameter defaults
);
You could constrain your route:
routes.MapRoute(
"YourRouteName",
"{flightNumber}/{action}",
new { controller = "Home", action = "Index" },
new { flightNumber = #"\d+" }
);
Now it is required that you must always have a flightNumber which is one or more digits followed by an optional controller action.
Thus /5 will hit the Index action of Home controller and pass it flightNumber = 5 parameter and /5/admin would hit the Admin action of Home controller passing it flightNumber = 5 parameter.
Now if your ids are not integers but strings things will get complicated because the routing engine will no longer be able to disambiguate your routes. You could constrain the action part to a list of possible actions using a RegEx but find that approach a bit limiting because if someone adds a new action to the Home controller he would also need to update the route constraint.

How to route Dynamic Controller/Action Pattern in MVC 4 -Routing for ASP.net MVC 4

I hope it is a better way to write the route in MVC 4 and would like some feedback.
Could you let me know if the routing patterns below are the best way to do it in MVC 4?
I have an application that has a requirement to show the url in the following format.
http://domain.com/777-777-7777-777-7777/Page1
http://domain.com/777-777-7777-777-7777/Page2
The 777-777-7777-777-7777 is an account number. PageX is the report page number.
I am trying to avoid trashing other controller routes in my project.
Below is what I tried but need feedback if this will trash future controllers.
Report Number plus page route
routes.MapRoute(
"Report", // Route name
"{AccountNumber}/{ReportPage}",  
new { controller = "Report", action = "Navigate", AccountNumber = UrlParameter.Optional, ReportPage = UrlParameter.Optional});
Future Controller I don't want to trash.
routes.MapRoute(
"FutureController", // Route name
"FutureController/{action}/{id}",  
new { controller = "FutureController",id= UrlParameter.Optional});
Any feedback is appreciated.
I believe ur routes are OK. Its not gonna break with current setup. Only thing to remember when writing routes is that you put more specific routes first because they are processed in order and first matching route is picked by url engine. I must however say that your ReportPage parameter would contains values like page1 and page1 instead of numeric 1 or 2. I have seen someone writing rules where only the numeric portion would be received in action result. As far as I can remember it was something like
routes.MapRoute(
"Report", // Route name
"{AccountNumber}/page{ReportPage}",
new { controller = "Report", action = "Navigate", AccountNumber = UrlParameter.Optional, ReportPage = UrlParameter.Optional},new{ReportPage = "\d+"});
This way you will have urls like http://domain.com/account/page1 but in action methods you will receive the numeric values for ReportPage parameter. It would, however, not match when page number is absent. For this scenario you can add another route like the guy recommended in answer to this question

MVC Routing: Trying to get dynamic root value working

I am trying to define dynamic sections of my site with the root url of the site. I am having some trouble defining the right MVC Route for it. Can someone please help.
My desired url will look like this: http://website.com/[dynamic-string]
But I have other standard pages like: http://website.com/about or http://website.com/faq or even just http://website.com.
My routes don't work correctly with that dynamic string. As shown below.
This is the route for the dynamic-string.
routes.MapRoute(
"CommunityName", // Route name
"{communityName}", // URL with parameters
new { controller = "Community", action = "Community", communityName = UrlParameter.Optional }
);
This is the route for all other STANDARD PAGES
routes.MapRoute(
"Default", // Route name
"{action}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
My routes just don't match up. Everything either gets diverted to one or the other route depending on which route is declared first.
There is no difference between the two routes you mention. How can MVC know which url should be mapped to communityName and which to action? Any url can match both.
You can define your standard pages as a route (before the CommunityName route) or you can catch them in your Community action, see if the name matches a function in your Home controller and then call the right action function.
I've never done this before but you might be able to create a more intelligent routehandler that looks at your controller actions, checks if the action really exists and if true selects that route.
this is beacuse the routes are effectively the same. When you declare the action route you do not state any constraints to the route, for this reason anything will be assumed to be a the action name.
If you want two routes to capture at the same level then you must constrain the action names to those that exist on your controller, this way if it does not match it will pass to the next route.
You can see an example of and advanced constraint here:
http://blogs.planetcloud.co.uk/mygreatdiscovery/post/Custom-route-constraint-to-validate-against-a-list.aspx

ASP.NET MVC: Many routes -> always only one controller

I have very simple question. My site, based on ASP.NET MVC, can have many urls, but all of them should bring to the one controller. How to do that?
I suppose I need some magic in Global.asax but I don't know how to create route that will redirect any url to the specific controller.
For example I have url /about, /product/id etc. but all of them should be really bring to the content/show where the parts of url will be recognized and the decision what information to show will be make. It's some like CMS when you cannot define routes in advance. Is this information enough?
Thanks
This sounds like a horrible idea, but, well, if you must;
routes.MapRoute(
"ReallyBadIdea",
"{*url}",
new { controller = "MyFatController", action = "MySingleAction" }
);
This routes everything to a single action in a single controller. There's also {*path} and other URL patterns should you want slightly more flexibility.
Ideally you should try and specific with your routes, for example if you have a URL that is /products/42 and you want it to go to a generic controller you should specify it explicitly like
routes.MapRoute(
"Poducts",
"products/{id}",
new { controller = "Content", action = "Show", id = UrlParameter.Optional }
);
then you would specify another route for something else like /customers/42
routes.MapRoute(
"Customers",
"customers/{id}",
new { controller = "Content", action = "Show", id = UrlParameter.Optional }
);
this may seem a little verbose, and creating a single route might seem cleaner, but the issue a single route is you will never get a 404 and will have to handle such things in code.

Resources