MVC 3 Fall-through routing - asp.net

Sorry for asking a rather n00b question, I am rather new to ASP.NET MVC.
My problem is as follows:
I want my site to handle a URL in the following way:
www.mysite.com/homepage/name
I want the above link to go to that user's profile. For simplicity the controller will be the Homepage controller with the Test action.
Meaning that the global.asax routing will be:
routes.MapRoute(
"test",
"homepage/{name}",
new { controller = "Homepage", action = "Test" }
);
Up until now the code works great (I have tested it and it routes ok).
But now my other functionality which I want is to enable:
www.mysite.com/homepage/action/id
To work as well.
The routing for this will be:
routes.MapRoute(
"Default",
"homepage/{action}/{id}",
new { controller = "Homepage", action = "Index", id = UrlParameter.Optional }
);
The problem is what happens when a user wants to omit the {id} for an action, the routing table detects that the action name is actually the {name} parameter.
Is there any way to first CHECK if an action exists. And only if it doesn't, then use it as a parameter for a different route.
Makes sense? if not I'll add some more details.
Thanks!
EDIT
So I've managed to solve this using the constraints regex
I placed a regex defining a all the actions in my controller:
routes.MapRoute(
"homepage",
"homepage/{action}/{id}",
new { controller = "Homepage", action = "Index", id = UrlParameter.Optional },
new { action = "(action1|action2|action3)" }
);
And then the next rule:
routes.MapRoute(
"feed",
"homepage/{id}",
new { controller = "Homepage", action = "Test"}
);
I works ok, only it's hard to scale upon this. You need to remember to place every new action on the controller inside the string here. It's a huge opening for debug nightmares.
Thank you !

Since ASP.NET MVC selects the first route from the RouteTable that matches the current request, you should be able to fix this problem by changing the order of the routes in the Global.asax.
First this:
routes.MapRoute(
"Default",
"homepage/{action}/{id}",
new { controller = "Homepage", action = "Index", id = UrlParameter.Optional }
);
and then this:
routes.MapRoute(
"test",
"homepage/{name}",
new { controller = "Homepage", action = "Test" }
);
Hope this helps.

You need to put the Default route first, and also restrict its allowed values
routes.MapRoute(
"Default",
"homepage/{action}/{id}",
new { controller = "Homepage", action = "Index", id = UrlParameter.Optional },
new {action = #"Index|Delete|Add"}
);
routes.MapRoute(
"test",
"homepage/{name}",
new { controller = "Homepage", action = "Test" }
);
This way the first route will only be used if the action value matches one provided in the constraint, otherwise it will move to the next rule.
You will also have to make sure when you create user profiles, that no name should match one of your supported actions for the default route.

Related

Trying to route parameters to catch all index action on home controller

I am trying to capture parameters into the default home mvc controller which till now I didn't need to do as angular is taking care of all the views/routing.
The reason for this is because I was using angular to set metadata for the SEO. That doesn't work as angular is purely client side. The SEO has to come from the server.
My home controller route is simply this which is a catch all right now, so it needs to stay a catch all but also receive any extra parameters
routes.MapRoute(
name: "Default",
url: "{*.}",
defaults: new { controller = "Home", action = "Index" }
);
So I can capture something in the url like this ie 'product'
public ActionResult Index(string product = "")
{
var meta = new MetaData
{
Title = "Test",
Description = "Desc1",
Keywords = ""
};
return View("Index",meta);
}
I can't use something like
url: "{controller}/{action}/{id}",
Because then it will expect views/controllers for my other pages which are taken care of by angular.
So I need a default route that will use the home controller whenever the url is like this
mywebsitename.com/showmen
I tried
url: "*./{product}",
but that is invalid. I also changed the route to
routes.MapRoute(
name: "Default",
url: "{*.}",
defaults: new { controller = "Home", action = "Index" , product = UrlParameter.Optional}
);
But that doesn't work.
I removed the catch all route and just used a default one like this for the home page
routes.MapRoute(
name: "HomePage",
url: "",
defaults: new
{
controller = "Home",
action = "Index",
id = UrlParameter.Optional
}
);
Without the catch all I had to add quite a few routes for the other pages like this
routes.MapRoute(
name: "LandingPage",
url: "landingpage/{product}",
defaults: new
{
controller = "Home",
action = "Landing",
product = UrlParameter.Optional
}
);
So now i can capture the product and send the metadata to _Layout using the same index view. Meanwhile the angular route still does what it did before.
Anything that receives a quoteref/password all use a generic route that passes to the home controller index action to update the same model on _Layout.

How create RouteLink with custom routes registered in route config?

Im having this routes in RouteConfig:
routes.MapRoute(
name: "AdminGroupsEdit",
url: "admin/groups/{id}",
defaults: new { controller = "Group", action = "Edit" }
);
routes.MapRoute(
name: "AdminGroupsEditStudent",
url: "admin/groups/{id}/students/{studentid}",
defaults: new { controller = "Student", action = "Edit" }
);
routes.MapRoute(
name: "AdminGroupsCreateStudent",
url: "admin/groups/{groupId}/students/create-student",
defaults: new { controller = "Student", action = "Create" }
);
When im on page with iri:
admin/groups/1
there is a RouteLink:
#Html.RouteLink("Add", routeName: "AdminGroupsCreateStudent", routeValues: null, htmlAttributes: new { #class = "btn btn-success" })
But when i clicked on it asp.net going to route with name "AdminGroupsEdit".
How can i create RouteLink to go to route with name "AdminGroupsCreateStudent"? If i need to pass groupId throw routeValues so how can i get it from Uri?
Couple of issues I can see with the way your currently routing so I've detailed below along with recommendations to resolve.
In your example, all that the routing engine is able to understand is that your attempting to create a Url to the route name AdminGroupsCreateStudent. The routing engine is able to confirm it has a route with the name AdminGroupsCreateStudent, but then when trying to match the route values against the parameters, it's unable to continue as you've attempted to pass null and this route needs a parameter of groupId in order to succeed so it returns the route referring to the page your on.
By creating a parameter mid-way into the Url, the routing engine
expects a value for the route to render successfully. Sadly even attempting to assign the groupId parameter with the value UrlParameter.Optional, You would still end up with the same issue during runtime as once again the engine would is unable to do anything with a null parameter in the middle of Url as it cleverly knows it would break the link and is the reason why parameters are placed at the end or have default values.
My recommendation's would be to do either of the following:
Add groupId to the end of the routes Url and set the default value to UrlParameter.Optional.
routes.MapRoute(
name: "AdminGroupsCreateStudent",
url: "admin/groups/students/create-student/{groupId}",
defaults: new { controller = "Student", action = "Create", groupId = UrlParameter.Optional }
);
Or if you need to have this Url in place, then just set a default value for groupId to handle the null and then manage the logic for this value in the Create action.
routes.MapRoute(
name: "AdminGroupsCreateStudent",
url: "admin/groups/{groupId}/students/create-student",
defaults: new { controller = "Student", action = "Create", groupId = 0 } //0 == Unknown
);

Asp.Net: Removing the action name from the URL

I am trying to create a routing rule that allows me to use
http://localhost:*****/Profile/2
instead of
http://localhost:*****/Profile/Show/2
to access a page. I currently have a routing rule that successfully removes index when accessing a page. How do I apply the same concept to this?
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
I have a couple of questions to clarify what you are trying to do. Because there could be some unintended consequences to creating a custom route.
1) Do you only want this route to apply to the Profile controller?
Try adding this route before the default route..
routes.MapRoute(
name: "Profile",
url: "Profile/{id}",
defaults: new { controller = "Profile", action = "Show" }
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
This new route completely gets rid of the Index and other actions in the Profile controller. The route also only applies to the Profile controller, so your other controllers will still work fine.
You can add a regular expression to the "id" definition so that this route only gets used if the id is a number as follows. This would allow you to use other actions in the Profile controller again as well.
routes.MapRoute(
name: "Profile",
url: "Profile/{id}",
defaults: new { controller = "Profile", action = "Show" }
defaults: new { id= #"\d+" }
);
Also, it would be a good idea to test various urls to see which route would be used for each of the urls. Go to NuGet and add the "routedebugger"
package. You can get information on how to use it at http://haacked.com/archive/2008/03/13/url-routing-debugger.aspx/

ASP.NET MVC routing: URL is falling into the wrong route

I'm working into a really common mvc Project and I have three diferents routes:
Route for display products by id
routes.MapRoute(
"get-by-id",
"{controller}/{id}",
new { action = "GetById" },
new { id = #"\d+" }
);
Route for display products by category
routes.MapRoute(
"get-by-category",
"{controller}/{category}",
new { action = "GetByCategory" },
new { category = #"\w+" }
);
Default route
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Conslusion: I want the /products/create request falls into the default route (because I want "create" to be rendered as an action) and not into the get-by-category route (because it take "create" as a string).
Use Route Debuger it will help you debug your routes to figure out which routes are being called when. One of the tools I always nuget when working on asp.net mvc.
BTW - looking at your routes there is no route there that maps to Product/Create. In which case it is just going to take you to the default route. You need to have a route specified which is going to map to the Products controller and if you want to have an action of Create it will need to have "Products/Create" with its action pointing to Get-by-id action
routes.MapRoute(
"get-by-id",
"{controller}/Create/{id}",
new { action = "GetById" },
new { id = #"\d+" }
);

MVC+ Url Routing+adding additional paramters

I have a url like http://mysite.ef.com/mine . It internally needs to redirect to
http://mysite.ef.com/Product/ViewProduct/2. The last parameter(i.e 2) has to be derived from last paramter of the first url (in this case the value is "mine") by hitting the database to see if it is valid and if it is valid get the correct id. How can we accomplish it using Url Routing. I could validate it by using custom constraint but how to rewrite the url with this fetched value.
Regards
Raghav
Get your routing configuration to look like this:
routes.MapRoute(
name: "ProductRouting",
url: "{id}",
defaults: new { controller = "Product", action = "ProductView", id = UrlParameter.Optional },
namespaces: new[] { "YourApp.Controllers" }
);
Beware though, as the usual default route looks like this and if you just pass one parameter that usually specifies just the controller, but in your case it will specify the product id.
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Account", action = "Login", id = UrlParameter.Optional },
namespaces: new[] { "YourApp.Controllers" }
);
If you somehow need it to perform a lookup and work out that mine corresponds to product 2, your ProductView ActionMethod needs to take in a string and perform a simple lookup.

Resources