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

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+" }
);

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/

how to carry culture parameter in url as routing parameter not request parameter?

I want to create a custom routing system ASP.NET MVC 4 project to make my website multilingual. and I want to carry culture parameter in url like localhost/en/controllerName/actionName. but the problem is when I write for example localhost/home routing engine supposes "home" as culture name. How can I solve this problem?
If all your routes will enforce culture parameter, you can use something like:
routes.MapRoute(
name: "LocalizedDefault",
url: "{lang}/{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
constraints: new { lang = #"(es|en|fr)" }
);
If you still want to respond to localhost/home, just let the default route after the one above, that way the first one will not match because of the constraints and fall back to the second:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

MVC 3 Fall-through routing

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.

Resources