MVC4: same url base for different actions - c#

I would like to have 2 routes similar to these:
routes.MapRoute("Detail", "guide/{urlname}", new { controller = "Application", action = "Detail" });
routes.MapRoute("Search", "guide/{keyword1}/{keyword2}", new { controller = "Guide", action = "Index", keyword1 = UrlParameter.Optional, keyword2 = UrlParameter.Optional });
So one route is a detail page that looks up an object in the database based on its url name, and the other route is a search results page based on application-generated keywords, both of which share the same url root (/guide). The two actions are in different controllers. Possible urls are:
/guide/evernote --> should route to the application detail page
/guide --> should route to search results without filter
/guide/iphone --> should route to iphone apps search results
/guide/iphone/medical --> should route to medical iphone apps search results
Obviously, like this, the second route will never be matched for a url like /guide/iphone because the first route will already match the same url.
I don't want to do a redirect in the first action if the controller can't find the object in the database. So what other alternatives are there? Do I need to create a custom RouteHandler or UrlRoutingModule for this or is there a simpler way?

If {urlname} is a url like it implies, you can add a constraint to test if the url matches a regex:
http://www.asp.net/mvc/tutorials/controllers-and-routing/creating-a-route-constraint-cs

Change the order and it will work:
routes.MapRoute("Search", "guide/{keyword1}/{keyword2}", new { controller = "Guide", action = "Index" });
routes.MapRoute("Detail", "guide/{urlname}", new { controller = "Application", action = "Detail" });

Related

Generating URLs for ASP.NET MVC Area routing with subfolder

I have an ASP.NET MVC app which has areas with special routes as following:
Area registration file:
context.Routes.MapHttpRoute(
"AccessControlApi_default",
"accesscontrol/api/{controller}/{id}",
new { id = RouteParameter.Optional }
);
context.MapRoute(
"AccessControl_dashboardwidgets",
"accesscontrol/dashboardwidgets/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional },
new[] { "AccessControl.Controllers.DashboardWidgets" }
);
context.MapRoute(
"AccessControl_default",
"accesscontrol/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional },
new[] { "AccessControl.Controllers" }
);
First routing is for api, second is for controllers and views in a sub-folder under the area, and third is for the default controllers under area.
Everything is working well with routing, but the issue is with the use of Url.Action like this one:
<a href='#Url.Action("Index","Home",new{area="AccessControl"})'>Go to home</a>
It's always injecting dashboardwidgets keyword in the url between area and controller like this: {host}/accesscontrol/dashboardwidgets/Home/Index
How can I generate urls according to my needs, either to root of area, or to this sub folder under the area??
I think the solution would be to use named routes in constructing your links. You would need to switch the call from
#Url.Action("Index","Home",new{area="AccessControl"})
to
#Url.RouteUrl("AccessControl_dashboardwidgets", new {area = "AccessControl", controller="Home", action="Index"})
or
#Url.RouteUrl("AccessControl_default", new {area = "AccessControl", controller="Home", action="Index"})
Depending on which route you are aiming for.
Sorry about the confusion with the parameters, was editing while doing something else... multitasking on Monday morning is obviously to be avoided:)
In order to use #Url.Action extension method you need to specify httproute name for routeValues parameter like that:
#Url.Action("Index","Home", new { httproute ="AccessControlApi_default"} )

How do I allow /Controller/Id in ASP.NET MVC?

I want to visit this url
/thread/123
Where 123 is the thread id.
I can't figure out how to set up my routes or whatever it is.
I thought to add thread to my HomeController, but it appears that it only works if I go to /home/thread.
How do I set up this project so the url /thread/123 will work?
I tried /thread as a controller but it seemed like it thought 123 was an Action Method and the other attempt had thread be in Home rather then root.
You want to add a Route designated for this URI
routes.MapRoute(
"Thread", // Route name
"thread/{id}", // URL with parameters*
new { controller = "Thread", action = "Display", id = UrlParameter.Optional }
);
very important: Add your new route ABOVE the "Default" Route!

Drop Route Values on Redirect

So, I've been trying for a few hours now to workaround something that should theoretically be very simple. Let's take this sample url:
http://sample.com/products/in/texas/dallas
This maps onto a specific route:
routes.MapRoute(
"products",
"products/in/{state}/{city}",
new { controller = "Products", action = "List", state = UrlParameter.Optional, city = UrlParameter.Optional });
In my action method, I can do lookups to make sure "texas" and "dallas" exist, and that "dallas" exists within Texas. That's all fine and dandy. However, in the situation where the city doesnt exist (either because the geo is incorrect, or mispelled), I want it to back up the state level. Example:
http://sample.com/products/in/texas/dallax
That should issue a redirect to
http://sample.com/products/in/texas
The "easy" way to do this was to simply issue a Redirect call like so:
return Redirect("/products/in/" + stateName);
However, I'm trying to decouple this from the URL structure; for example, if we ever decided to change how the route looks (say, change the pattern to products/around/{state}/{city}), then I would have to know that I need to make updates to this controller to fix the URL redirect.
If I can make a solution that just inspects the route values and can figure things out, then I don't have to worry if I change the route pattern, because the route values could still be figured out.
Ideally, I would have liked to do something like this:
return RedirectToRoute(new { controller = "Products", action = "List", state = state });
(Note, that is is a simplified example; the "required" route pieces like controller name and action method name would be determined by Generic argument and Expression inspection respectively).
That actually performs the redirect, HOWEVER, the route values from the current request get appended onto the redirect and thus you get in a redirect loop (note that I didn't include the city route value in the route object). How do I stop the "city" route value from being included in this redirect?
I've tried the following things to get rid of the route value:
Compose my own RouteValueDictionary / anonymous route data object and pass that to the overload of RedirectToRoute.
Create my own action result to inspect RouteTable.Routes and find the route myself, and do the replacement of the tokens myself. This seems the most "kludgy", and would seem to be re-inventing the wheel.
Make a method like RedirectWithout that takes a key value and calls RedirectToRouteResult.RouteValues.Remove(key) - which also didnt work.
I've also attempted to add a null value for the key I don't want to add; however, this alters the route to something that isnt correct - ie new { controller = "Products", action = "List", state = stateName, city = (string)null } issues a redirect to /Products/List?state=Texas which is not the right URL.
It all seems to stem from the RedirectToRoute taking the current request context to construct the virtual path data. Is there a workaround?
If you were using T4MVC, you should be able to do something like this:
return RedirectToAction(MVC.Products.List(state, null));
Have you tried this?
return RedirectToRoute(new
{
controller = "Products",
action = "List",
state = state,
city = null,
});
Reply to comments
Maybe MVC is confused because your optional parameter is not at the end. The below should work with the above RedirectToRoute that specifies city = null:
routes.MapRoute(
"products",
"products/in/{state}/{city}",
new
{
controller = "Products",
action = "List",
// state = UrlParameter.Optional, // only let the last parameter be optional
city = UrlParameter.Optional
});
You can then add another route to handle URL's where state is optional:
routes.MapRoute(null, // I never name my routes
"products/in/{state}",
new
{
controller = "Products",
action = "List",
state = UrlParameter.Optional
});

Dynamic ASP.net MVC Routing

I have a need for some dynamic routing. So my routes would look like this:
{UserName}
{UserName}/Edit/{id}
{UserName}/Delete/{id}
Where the users would be routed to the user controller. But I still want to maintain routes to controls like:
{Controller}/Edit/{id}
{Controller}/Delete/{id}
So basically I want it to direct to the physical controller say called OrdersController for edit delete but if someone navigates to /jdoe/ it sends it to the user controller.
How do I do this in my routes?
You need to create multiple routes, and keep them in the appropriate order
// one route for Users
routes.MapRoute("Users",
"{username}/{action}/{id}",
new { controller = "Users", action = "Index", username = string.Empty, id = UrlParameter.Optional },
new { id = #"\d+" }
);
// one route for everything else
routes.MapRoute("Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional},
new { id = #"\d+" }
);
It's not "really" as easy as above, but that's the jist of it. You would need too add a RouteConstraint to validate usernames.
Lastly, if you're using the username parameter, then why do you need the id? Just a thought.
Aside:
If you look at the user section here on StackOverflow, you'll see the routing look more like this.
users/{id}/{username}
users/{id}/edit
users/{id}/delete
I would personally say that this is a lot less work to achieve... but hey, that's just me.

MVC URL not rewriting

I'm trying to change the URL displayed in the user's browser from Happy/Balloons to happy-times/balloon-pops. There are many links in the project to the action "Balloons", so rather than change those links I'd like to change the global.asax so that a different URL appears for the same action. The original MVC Route looks like:
routes.MapRoute(
"Happy.Balloons",
"Happy/Balloons/{groupId}/{paymentType}/{mortgageValue}/{province}",
new { controller = "Happy", action = "Balloons" },
new { groupId = "\\d+", paymentType = "\\d+", mortgageValue = "\\d+", province = "\\d+" }
);
I've changed the code to
routes.MapRoute(
"Happy.Balloons",
"happy-times/balloon-pops/{groupId}/{paymentType}/{mortgageValue}/{province}",
new { controller = "Happy", action = "Balloons" },
new { groupId = "\\d+", paymentType = "\\d+", mortgageValue = "\\d+", province = "\\d+" }
);
I thought this second parameter was the URL displayed, but I'm getting a: "The resource you are looking for has been removed, had its name changed, or is temporarily unavailable." error. Is there a simple way to do this by modifying parameters in MapRoute? If so, how?
Question Follow-up: Change URL of action in mvc
this works, (replacing urlParameter.Optional to default values)
routes.MapRoute( _
"Happy.Balloons", _
"happy-times/ballons-pops/{groupId}/{paymentType}/{mortgageValue}/{province}", _
New With {.controller = "happy", .action = "Balloons", .groupId = UrlParameter.Optional, .paymentType = UrlParameter.Optional, .mortgageValue = UrlParameter.Optional, .province = UrlParameter.Optional} _
)
but... it's a bad practice (really bad one)
you can learn about route maps here
You're doing it wrong.
Changing the route mapping will not change the name of the controller. Change the controller and action name, and map your route as {controller}/{action} like it is by default. Then you can set your default controller and action as you have before.
Then your controller will have to be renamed to happy-times and your action renamed to balloon-pops
I should note that it will look more like this:
{controller}/{action}/{groupId}/{paymentType}/{mortgageValue}/{province}
Here's a good resource on the topic.
http://www.asp.net/mvc/tutorials/older-versions/controllers-and-routing/asp-net-mvc-routing-overview-cs
as brought to you by this SO post https://stackoverflow.com/a/2375293/1178921
**Looks like you might be trying to see more ways to do this.
This post talks about attributes you can use to route URLS differently.
ASP.NET MVC Routing Via Method Attributes
Additionally, your way of changing the url in the mapping CAN work, but isn't what I thought your intent was. Zach dev had this one dead on in that case. Your optional parameters need to be marked as such with UrlParameter.Optional

Categories

Resources