I have these 2 routes:
routes.MapRoute(
name: "First",
url: "{controller}/{id}/{action}",
defaults: null,
constraints: new { id = #"^\d+$" }
);
routes.MapRoute(
name: "Second",
url: "{controller}/{action}",
defaults: new { controller = "Home", action = "Index" }
);
The route handling works ok but the url generation does not work fine in all cases.
I'm trying to use the #Url.Action("Index"):
when I'm on "Home/List" it generates "Home/Index"
when I'm on "Home/1/Edit" it generates "Home/1/Index"
I can see a pattern here, but I don't know why it generates the urls like this, I would like to have the second form only when I explicitly pass in the "id" parameter.
I can use the following to solve my problem, but I'm not so excited about passing in route names:
#Url.RouteUrl("Second", new { action = "Index" })
Is there anything else I can do to have the helper work as expected?
Related
I want to implement a custom route in my MVC app and I just can't get it to work. I want to keep the exist default route as specified when you create your MVC app.
The routes I want to be valid should look like this:
default: /{controller}/{action}/{id}
new custom: /{controller}/{appid}/{action}/{id}
With the custom domain, I will be passing the appid in with every request, but the {id} should be optional. The routes are thus defined as follow:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Updates", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "NewPackageRoute",
url: "{controller}/{appid}/{action}/{id}",
defaults: new { controller = "apps", appid = "00000000000000000000", action = "Index", id = UrlParameter.Optional }
);
On the AppsController, I have an action method Index:
public ActionResult Index(string appid, string id)
If I supply the id parameter, this action method is hit as expected. I am expecting this method to also be called if the {id} parameter is not supplied, thus leaving the id parameter as null. This however does not happen.
How should I define my route differently? Should I perhaps rather make use of AttributeRouting for achieve my goal?
I should maybe also add... If I call the Search action on the Apps controller, I can get to the action. This would happen through the default route...
Hope I have all and enough info...
Oh my, but I guess I should've tried before I posted this. I left this issue for a day and now I got it working without any effort...
Thanks #StephenMuecke. You did point out the ordering of the routes which I forgot about. I played with the order initially, but at that point I had other issues in the route definitions that caused it not to work.
All I added was as length check on the appid route value and it is working... My routes are defined as follow now:
routes.MapRoute(
name: "NewPackageRoute",
url: "apps/{appid}/{action}/{id}",
defaults: new { controller = "Apps", action = "Index", id = UrlParameter.Optional },
constraints: new { appid = #"^[a-zA-Z0-9]{20}" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Updates", action = "Index", id = UrlParameter.Optional }
);
I'm trying to simplify the URLs in an application, and am struggling with the route registration. This is an administrative tool. In many cases we have a List view (List.cshtml) and a Details view (Index.cshtml). The pattern that I would like to implement for these URLs are as follows:
http://mysite/person/list (This view shows a list of people)
http://mysite/person/123 (View will show details for a person with an ID of 123)
Formatting the URls that way is more of a nice-to-have feature for polishing the site. I tried several routes, and in RouteConfig here are some of the more recent routes that I've tried.
routes.MapRoute(
name: "Person",
url: "Person/{action}/{id}",
defaults: new { controller = "Person", action = "Index" }
);
routes.MapRoute(
name: "PersonID",
url: "Person/{id}",
defaults: new { controller = "Person", action = "Index" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Dashboard", action = "Index", id = UrlParameter.Optional }
);
Now if I remove those custom routes, and just run with the default route, the "mysite/person/list" view works just fine. But when I select a person, the URL ends up being "mysite/person/index/[id]" instead of "mysite/person/[id]". And if I manually remove "index" from that URL and make the path "mysite/person/[id]", a "resource cannot be found" message appears.
In that second route shown, I figured that giving the route a default action would route to the Index page and treat the ID in the URL as an ID, rather than as an action. With the current configuration shown above, if I navigate to the Person/List view I'm routed to the Person/Index view.
There are a few other actions associated with that controller (like JsonResults), which I'll need to handle as well.
What is the correct way to write the routes to support the URLs that I've indicated above? Also, can you recommend a resource that shows multiple examples of route-to-URL comparisons? Thanks for your help!
=== Edit 4/9/2015 at 10:21 AM ===
Based on the answer provided by #stephen-reindl, this is the solution that I implemented. Since we have multiple interfaces with a "Detail" view, I chose a default action of "Detail". This route recognizes a GUID.
// Support URL format of http://mysite/{controller}/{guid}
// Example: http://mysite/person/474f4357-39b2-45a2-b02b-6be04b2302fe
routes.MapRoute(
name: "DetailViewWithGuid",
url: "{controller}/{id}",
constraints: new { id = #"\b[A-F0-9]{8}(?:-[A-F0-9]{4}){3}-[A-F0-9]{12}\b" },
defaults: new { action = "Detail", id = UrlParameter.Optional }
);
You can add a constraint that a specific route is only taken into consideration if the constraint is fulfilled:
routes.MapRoute(
name: "PersonID",
url: "Person/{id}",
constraints: new { id = #"\d+" },
defaults: new { controller = "Person", action = "Index", id = UrlParameter.Optional }
);
In this case this route is only taken if id is a number.
Okay, I've got this case where I have two controllers:
HomeController
MathController
I want the routing for my HomeController to stay as default:{controller}/{action}/{id}. But I want to access the actions in the MathController with http://myurl/Task/Math/{action}.
So what I've done is to write my RouteConfig like this:
routes.MapRoute(
name: "Math",
url: "Task/{controller}/{action}",
defaults: new { controller = "Math", action = "Index" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Hem", id = UrlParameter.Optional }
);
When using the above configuration and manually entering the URLs in the browser both routing methods are working. Though when trying to add a "actionLink" it always uses the Task/{Controller}/{Action} route. Even if I'm creating a link for the Home controller like this: #Html.ActionLink("Hem", "Hem", "Home", null, new { #class = "navbar-brand" })
How do I configure either my routing or my action links so that I'll get the preferred functionality?
Routes match from top down in RouteConfig.cs. Your problem is that both route configs are "catch all" routes, which means both work for any controller/action. When you use #Html.ActionLink, MVC will render the url based on the 1st route it finds, which matches your "Task" path. There are few ways to change this to get what you want.
If you want to only use the "Task" path for the Math controller, then I'd change your route to this:
routes.MapRoute(
name: "Math",
url: "Task/Math/{action}",
defaults: new { controller = "Math", action = "Index" }
);
If you want to use several controllers for the "Task" path, then you can add a route constraint. You can use it like below and specify a list of controllers (regex), or you can create your own custom Route Constraint class and implement whatever functionality you want.
routes.MapRoute(
name: "Math",
url: "Task/{controller}/{action}",
defaults: new { controller = "Math", action = "Index" },
constraints: new { controller = "Math|OtherController" }
);
Or if you want to keep all controllers/actions matching both urls, then you have to flip your routes to get the default route to display first, or you can use #Html.RouteLink like so:
#Html.RouteLink("Hem", "Default", new { controller = "Home", action = "Hem" }, new { #class = "navbar-brand" })
I'm having trouble doing what I want to achieve when doing routing in ASP.NET MVC.
What I want to do is the following:
When typing http://localhost/MyWebsite/, I want to redirect to http://localhost/MyWebsite/Login/ (The redirection to the action Index is implied here)
When typing http://localhost/MyWebsite/MyAction, I want to redirect to http://localhost/MyWebsite/Login/MyAction
Point 1 was achieved using the following lines in the file RouteConfig.cs:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Login", action = "Index", id = UrlParameter.Optional });
But I cannot accomplish point 2. Note that the user does not come from another action in a controller, but actually types the address in his browser.
Thanks for your help.
since /MyWebsite/Login and /MyWebsite/MyAction both have two segments in the URL, they're both matching your defined Route.
You can use a Route Constraint to only match /MyWebsite/Login to your first point, followed by a modified second route mapping:
routes.MapRoute(
name: "Default",
url: "MyWebsite/Login/",
defaults: new { controller = "Login", action = "Index", id = UrlParameter.Optional });
routes.MapRoute(
name: "Actions",
url: "MyWebsite/{action}/",
defaults: new { controller = "Login", action = "Index", id = UrlParameter.Optional });
I have an web app build with asp.net MVC 4.
I want to have the following 3 types of routes:
/action
/action/id
/id/id2
In global.asax I have changed the routes as it follows:
routes.MapRoute(
name: "Without Action",
url: "{id}/{id2}",
defaults: new { controller = "Home", action = "City_Category" },
namespaces: new[] { "Namespace.Controllers" }
);
routes.MapRoute(
name: "Without Controller",
url: "{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "Namespace.Controllers" }
);
But when I try an {action}/{id} it goes to the first route defined in global.asax. Works only if url is {action} or {id}/{id2}.
How can I make to work all 3 routes?
Thanks!
If {id} and {id2} will always be numeric, you can add a constraint to the route so that it will only kick in when those values are digits:
routes.MapRoute(
name: "Without Action",
url: "{id}/{id2}",
defaults: new { controller = "Home", action = "City_Category" },
new { id = #"\d+", id2 = #"\d+" }
namespaces: new[] { "Namespace.Controllers" }
);
Another idea is to use http://attributerouting.net/, you can define routes by attributes, which is a very easy to define routes, especially if you end up with a lot of complex routes. I had about 30 route definitions and a lot of comments how the url looks like for each action. I could remove all comments and route definitions with these attributes.