Recently I've made the transition from Web Forms to MVC 3 and I've been trying to get to grips with MVC routes. I have a somewhat peculiar problem in that when I receive a request to my application (e.g. subdomain1.organisation.com or subdomain2.organisation.com) I wish the default route to be used as follows:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
However, when a request is received by my application through a particular subdomain e.g. subdomain3.organisation.com, I want the application to default to a particular controller. I've been following code at:
http://blog.maartenballiauw.be/post/2009/05/20/ASPNET-MVC-Domain-Routing.aspx
which should what I want. So the code in my Global.asax is as follows:
routes.Add("DomainRoute", new DomainRoute(
"subdomain3.organisation.com", // Domain with parameters
"{action}/{id}", // URL with parameters
new { controller = "Subdomain3Controller", action = "Index", id = "" }
));
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
When deployed, my application behaves correctly when requests are sent to subdomain3.organisation.com, using Subdomain3Controller. However, when visiting any other subdomain e.g. localhost/Subdomain3Controller/Index my application seems to select the incorrect route.
My form helpers appear to return an incorrect value for:
ViewContext.Controller.ValueProvider.GetValue("controller").AttemptedValue
#using(Html.BeginForm(ViewContext.Controller.ValueProvider.GetValue("action").AttemptedValue, ViewContext.Controller.ValueProvider.GetValue("controller").AttemptedValue, FormMethod.Post, new Dictionary<string, object> {{ "id", "formid" } })){
Any ideas why this might be? Any light that anyone could shed on this issue would be much appreciated.
Many thanks in advance.
Have you tried the routing debugger, which is designed to help debug these sorts of problems
Looks like it's installable via Nuget now too.
I've also noticed that if I hard-code the controller name into the BeginForm helper, the incorrect action value is still returned:
using (Html.BeginForm("Index", "Subdomain3Controller", FormMethod.Post, new Dictionary<string, object> { { "id", "formid" } }))
{
generates:
<form id="formid" method="post" action="/">
rather than:
<form id="formid" method="post" action="/Subdomain3Controller">
when viewing:
http://localhost/Subdomain3Controller/ or http://localhost/Subdomain3Controller/Index
Stumbled on a similar problem and managed to find a solution for this problem. I'm aware this might not help the original author, but it might help some other people who end up here via search.
Anyway, it seems the route name "Default" doesn't add much weight. When BeginForm is constructing its URL it takes the first route from the route collection that 'fits'. I didn't dig too deep into how this all works internally.
What I did to solve this problem was add a constraint to the subdomain route so it can only be used for the Subdomain3Controller, as such:
var domainRoute = new DomainRoute(
"subdomain3.organisation.com", // Domain with parameters
"{action}/{id}", // URL with parameters
new { controller = "Subdomain3Controller", action = "Index", id = "" }
);
domainRoute.Constraints = new RouteValueDictionary();
webserviceRoute.Constraints.Add("Controller", "Subdomain3Controller");
routes.Add("DomainRoute", domainRoute);
[edit]
After thinking about this a little bit more and realizing my situation was a bit different from the situation of the original poster. The above won't work, because the controller is not inside of the URL anymore.
A solution might be to switch the order of the routes, and add a NotEqual constraint for the subdomains to the default route. As described in http://stephenwalther.com/archive/2008/08/07/asp-net-mvc-tip-30-create-custom-route-constraints.aspx
[/edit]
Related
I have this following url:
http://www.example.com?user=Ana
and I want to get http://www.example.com?Ana
How can I get it?
You can route example.com/Ana to Home/Index with parameter (you can change controller and action to what is needed). Just add new route to your routing dictionary
routes.MapRoute(
"UserPage",
"{controller}/{action}/{user}",
new { controller = "Home", action = "Index", user = "" }
);
You can read more about routing here at ASP.NET
NOTE:
as Alexei Levenkov said it requires .Net MVC to route it that way.
I have an area called News, and within that area I have a Post Controller. The post controller has the following action:
public ActionResult Index(int id, string name)
{
...
}
I have a route in the NewsAreaRegistration
context.MapRoute(
"News_post",
"News/{controller}/{id}/{name}",
new { action = "Index", controller = "Post",name = UrlParameter.Optional }, new { id = #"\d+"}
);
I have also tried without the name object attribute, with and without the id #"\d+ .. Thing is I have this on another site with the exact same setup, just so confused at why it's not working as expected.
Now firstly, the action will resolve:
http://example.com/News/Post/Index/3
When I want it to resolve to
http://example.com/News/Post/3
And then I also want this string parameter at the end so it should resolve to
http://example.com/News/Post/3/test-post
but instead resolves to
http://example.com/News/Post/Index/3?test-post
I am having a total nightmare with this routing stuff. I have tried to mess around with the Routing attributes but also have no luck there with areas... Any ideas guys?
So I fixed part of the issue by making the Route look like this:
context.MapRoute(
"News",
"News/Post/{id}/{name}",
new { action = "Index", controller = "Post" },
new { id = #"\d+" }
);
So I removed the UrlParamter.Optional for the name argument. I need to really get my head around how some of these routes work. At times it is so easy, but then others I can't get it to do the simplest things.
I would like to have some paramaters after my website's URl.
So, mysite.com/ThisIsMyStringMessage, would show this :
Hello, ThisIsMyStringMessage.
Of course, the view related to the action contains this :
Hello, #ViewBag.Message
And the HomeController :
public ActionResult Index(string message)
{
ViewBag.Message = message;
return View();
}
Edit related to comments :
#Zim, I'll have more than one controller.
#Jessee, So that's what I'm doing here, thank you, I didn't know really what I was doing.
With the default routing, ThisIsMyStringMessage will be picked up as the Controller, not as an Action method parameter. You will need a custom route to be able to do this. Try the following before the default route in Global.asax:
routes.MapRoute(
"RootWithParameter",
"{message}",
new { controller = "Home", action = "Index", message = UrlParameter.Optional }
);
Alternatively, access the method with mysite.com?message=ThisIsMyStringMessage
You will need to take a look at your RouteConfig.cs or Global.asax to setup a route with the parameter of message instead of id. Right now it probably looks like:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
You would need to change the url parameter to something like {controller}/{action}/{message} for that to work.
Also, be careful with passing strings in the URL. ASP.NET (and some modern browsers) gives you many security protections to prevent people from doing nasty stuff like XSS, but it's probably not a habit you want to create.
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.
I thought I had at least a bases for understanding routing in MVC after all the documentation I have read, only to fail at it when attempting to utilize it.
I have the following two routes declared in my Global.aspx
routes.MapRoute(
"", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Admin", action = "List", id = UrlParameter.Optional } // Parameter defaults
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
I have a AdminController that I have a few methods, one that is "List" method that renders a list of products to a "List" view.
I thought I understood how RedirectToAction works, and I added an "Add" method (see below) that adds a new Product and returns a RedirectToAction which I understood would be the proper way to redirect to the List action on the same "AdminController"
[HttpPost]
public ActionResult Add(Product product) {
if (_prodRepo.Add(product)) {
return RedirectToAction("List", "Admin");
}
return View("Add", product);
}
However, on the return of the "Add" it always attempts to route to the path website.com/Account/Login/ReturnUrl=%2f.
However, if I go to website.com/Admin it does render the list as I expect. But when using the RedirectToAction as in the example above, it attempts to go to the /Account/Login (Controller/action).
It was my understanding that the RedirectToAction("List", "Admin") would route to the "List" method on the AdminController controller and that I was using it as expected.
Can someone please help me understand the reasoning behind this. But also, could someone post some recommended articles for understanding the whole MVC routing including how the web.config works with routing.
Finally, it was also my understanding that route discovery by the framework is done in the order they are specified in your routes.MapRoute() declaration and stops at the first one that matches. Therefore, if the first one is listed as Controller = "Admin", Action = "List", I would expect by convention that this is the correct route it would first match and return.
Your routes need to be different (the url parameter) since the first route with a matching url will be used.
This will therefore work for you:
routes.MapRoute("Admin",
"admin/{action}/{id}",
new { controller = "Admin", action = "List", id = UrlParameter.Optional });
The defaults (third parameter in the method) are used if the parameters isn't found/specified in the uri.
As for your question regarding /Account/Login/ReturnUrl=%2f. The login redirections are handled by the MembershipProvider and not by the standard routing mechanism.