I have 4 routes defined 5 different urls. Tested a lot with RouteDebugger but can not solve.
The problem is that Top 2 links always use {controller}/{action}/{id} this route which is root1 and can not redirect to proper pages.
Links
#Html.ActionLink("Go Index by name", "Page", "Home", new { name="contact"}, null)
#Html.ActionLink("Go Index by id", "Index", "Admin", new { id=2}, null)
#Html.ActionLink("Go Index by id and name", "Page", "Home", new { name = "contact", id = 2 }, null)
#Html.ActionLink("Root Admin", "Index", "Admin")
#Html.ActionLink("Root", "Index", "Home")
Here is the Map.Route
routes.MapRoute("root1",
"{controller}/{action}/{id}",
new { controller = "Admin", action = "Index" });
routes.MapRoute("root2",
"{controller}/{action}/{name}",
new { controller = "Home", action = "Page" });
routes.MapRoute("root3",
"{controller}/{action}/{name}/{id}",
new { controller = "Home", action = "Page" });
routes.MapRoute("root4",
"{controller}/{action}/{name}",
new { controller = "Home", action = "Index", name = UrlParameter.Optional });
These are the routes I have set up and it seems to hit each one correctly.
Note that root3 has been moved to the top since root2 will match that as well. also, the validation for root1 with id as King Julian suggested
The route:
#Html.ActionLink("Root Admin", "Index", "Admin")
should not match root1 nor root2 since there is no default for id and name respectively in the route definition
routes.MapRoute("root3",
"{controller}/{action}/{name}/{id}",
new { controller = "Home", action = "Page" });
routes.MapRoute("root1",
"{controller}/{action}/{id}",
new { controller = "Admin", action = "Index" },
new { id = #"\d+" });
routes.MapRoute("root2",
"{controller}/{action}/{name}",
new { controller = "Home", action = "Page" });
routes.MapRoute("root4",
"{controller}/{action}/{name}",
new { controller = "Home", action = "Index", name = UrlParameter.Optional
});
Add constraints to your routes. For example:
routes.MapRoute(
"root1",
"{controller}/{action}/{id}",
new { controller = "Admin", action = "Index" },
new {id = #"\d+" }
);
Will ensure that root1 only matches when id is an integer. Otherwise, root2 would catch it.
Related
I am looking to create a MVC3 website. We need at least two areas but we need different url's for each of the areas. Like this:
domain.com/ goes to /
admin.domain.com/ goes to /areas/admin
anotherSite.com/ goes to /areas/portal
After doing some research I have found Lucero's link that you can use HostNameContraint as follows:
public class HostNameContraint : IRouteConstraint
{
protected string _hostname;
public HostNameContraint(string hostname)
{
_hostname = hostname;
}
bool IRouteConstraint.Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
if (httpContext.Request.Url.Host == _hostname)
return true;
return false;
}
}
and then register the constraints like this:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { area = "", controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
new { hostname = new HostNameContraint("domain.com") },
new[] { "MVCProject.Controllers" }
);
routes.MapRoute(
"Admin_Default2", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { area = "Admin", controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
new { hostname = new HostNameContraint("admin.domain.com") },
new[] { "MVCProject.Controllers.Areas.Admin.Controllers" }
);
routes.MapRoute(
"Portal_Default2", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { area = "Portal", controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
new { hostname = new HostNameContraint("anotherSite.com") },
new[] { "MVCProject.Controllers.Areas.Portal.Controllers" }
);
I have IIS setup so that they point to the root folder of the application for each of the sites. Pointing to the root "Domain.com" works fine but going to either "Admin.domain.com" or "Domain.com/admin/" comes up with a 404 "Resource cannot be found."
Update
I have tried it both with the Area name at the beginning of the url and without.
"Portal/{controller}/{action}/{id}"
The issue is that when the "Portal" area is in the route, the signature does not match the name as "anotherSite.com" and therefore it comes back and says 403.14 - Forbidden. Cannot list contents of this directory. It is also important to note that the constructor for HostNameConstraint is never called when the "Portal" area is url parameter.
In order to indicate distinguish the URL as going to an area, the area name needs to be part of the URL. Otherwise, the area will not be parseable from the URL and you will fall back to the default routing. Also, it is a good idea to put your default route last - to ensure all other route mappings are tested
Note the addition of "Admin/" and "Portal/" in the corresponding MapRoute call:
routes.MapRoute(
"Admin_Default2", // Route name
"Admin/{controller}/{action}/{id}", // URL with parameters
new { area = "Admin", controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
new { hostname = new HostNameContraint("admin.domain.com") },
new[] { "MVCProject.Controllers.Areas.Admin.Controllers" }
);
routes.MapRoute(
"Portal_Default2", // Route name
"Portal/{controller}/{action}/{id}", // URL with parameters
new { area = "Portal", controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
new { hostname = new HostNameContraint("anotherSite.com") },
new[] { "MVCProject.Controllers.Areas.Portal.Controllers" }
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { area = "", controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
new { hostname = new HostNameContraint("domain.com") },
new[] { "MVCProject.Controllers" }
);
I have a module called News as Area. In NewsAreaRegistration I have
context.MapRoute(
"NewsShow",
"News/{controller}/{friendlyUrlName}/{idNews}",
new { controller = "Show", action = "Index", friendlyUrlName = "", idNews = "" }
);
In my view (in main View folder) I use RouteUrl method to enforce my custom route
#Url.RouteUrl("NewsShow", new { controller = "Show", action = "Index", friendlyUrlName = FriendlyURL.URLFriendly(true, Model.News.Data.ElementAt(0).Title), idNews = Model.News.Data.ElementAt(0).IdNews})"
What I would like to do is have a route like this www.something.com/News/Show/bla-bla-bla/9
without action name Index that I have in Show controller. I tried literaly all permutations of this example and nothing worked. Is this even possible?
Ok, so I tried this out....
Routing table: (before default)
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
routes.MapRoute(
name: "Hidden",
url: "News/{controller}/{friendlyUrlName}/{idNews}",
defaults: new {controller = "Home", action = "Index", friendlyUrlName = "", idNews = ""});
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Account", action = "Index", id = UrlParameter.Optional }
);
In the View:
#Url.RouteUrl("Hidden", new { friendlyUrlName = "Dude-Check-It-Out", idNews = 12 })
in my controller:
public ActionResult Index(string friendlyUrlName, int idNews)
{
ViewBag.Message = "Modify this template to kick-start your ASP.NET MVC application.";
ViewBag.UrlName = friendlyUrlName;
ViewBag.NewsId = idNews;
return View();
}
and I got this..
/News/Home/Dude-Check-It-Out/12
URL I go to:
http://localhost:49840/News/Home/Dude-Check-It-Out/12
I also changed my default route to something else to ensure that this wasn't using the default route. Let me know if this helped :)
Did you put this route before default one? Route position is important, from top to bottom.
Ok...I managed to work somehow.
In my NewsAreaRegistration I had to move NewsShow route before default. Not sure why, becuase RouteUrl should map excatly to NewsShow.
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"NewsShow",
"News/{controller}/{friendlyUrlName}/{idNews}",
new { controller = "Show", action = "Index", friendlyUrlName = "", idNews = "" }
);
context.MapRoute(
"News_default",
"News/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
This is my RouteUrl now (notice I had to write controller.Not sure exactly why either:
#Url.RouteUrl(
"NewsShow", new { controller = "Show", friendlyUrlName = FriendlyURL.URLFriendly(true, Model.News.Data.ElementAt(0).Title), idNews = Model.News.Data.ElementAt(0).IdNews }
);
Using the following code:
#Html.ActionLink("News", "Index", new { controller = "News", area = "" }, new { #class = "News" })
I'm getting an error so that when I'm on a particular news article, the link is generating as:
http://mywebsite/News/2011/12/2/my_slug
where the parameters match the page that I'm currently on. The also happens on other controllers matching the same url schema (imagine I have another controller called Presentations that matches the url scheme of News entirely). From the presentations pages, a link to news would include the presentations parameters which aren't valid input for the news controller. Make sense?
I have my routes defined as:
routes.MapRoute(
"News-Archive", // Route name
"News/Archive", // URL with parameters
new { controller = "News", action = "Archive" }, // Parameter defaults
new[] { "mywebsite.Controllers" }
);
routes.MapRoute(
"News-Stub", // Route name
"News/{year}/{month}/{date}/{slug}", // URL with parameters
new { controller = "News", action = "Index" }, // Parameter defaults
new[] { "mywebsite.Controllers" }
);
routes.MapRoute(
"News-ByDay", // Route name
"News/{year}/{month}/{day}", // URL with parameters
new { controller = "News", action = "Archive" }, // Parameter defaults
new[] { "mywebsite.Controllers" }
);
routes.MapRoute(
"News-ByMonth", // Route name
"News/{year}/{month}", // URL with parameters
new { controller = "News", action = "Archive" }, // Parameter defaults
new[] { "mywebsite.Controllers" }
);
routes.MapRoute(
"News-ByYear", // Route name
"News/{year}", // URL with parameters
new { controller = "News", action = "Archive" }, // Parameter defaults
new[] { "mywebsite.Controllers" }
);
routes.MapRoute(
"News-Default", // Route name
"News", // URL with parameters
new { controller = "News", action = "Index" }, // Parameter defaults
new[] { "mywebsite.Controllers" }
);
Can someone please explain if the problem lies in my use of Html.ActionLink or my route definitions?
EDIT:
Changing the Actionlink to:
#Html.ActionLink("News", "Index", new { controller = "News", area = "", year = string.Empty, month = string.Empty, day = string.Empty, slug = string.Empty}, null)
results in this when called from a presentation page (those values are for the presentation, not a valid news item):
http://mywebsite/News?year=2011&month=12&slug=seo_overview
Not sure why that's causing the rewriting to change.
The action link assumes the current slug since no slug was provided:
Use
ActionLink("News", "Index", new { controller = "News", area = "", slug="newslug"}, new { #class = "News" })
or
ActionLink("News", "Index", new { controller = "News", area = "", slug = null}, new { #class = "News" })
There is a chance that setting the slug = null would also re-use the current slug, in that case set the slug = Empty String.
How can I have an action link with two Ids. (I am using areas). The Id2 gets rendered as a querystring.
Controller
public ActionResult View(int id, int id2)
Route
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
context.MapRoute(
"Admin_default2",
"Admin/{controller}/{action}/{id}/{id2}",
new { action = "Index"}
);
ActionLink
#Html.ActionLink("Click", "News/View", new { area = "Admin", id = 1, id2 = 2 }, null)
Rendered Link
/Admin/News/View/1?id2=2
Expected Link
/Admin/News/View/1/2
Try adding the more specific route (Admin_default2) first.
So, your mapping code would look like:
context.MapRoute(
"Admin_default2",
"Admin/{controller}/{action}/{id}/{id2}",
new { action = "Index"}
);
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
If i go to mysite/Catalog it breaks. How can solve it?
routes.MapRoute(
"Localization", // Route name
"{lang}/{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", 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
);
routes.MapRoute(
"Root",
"",
new { controller = "Home", action = "Index", id = "" }
);
It will match your first route thinking "Catalog" is "lang". You need to create constraint for your localizations.
Following route should match requests prefixed with any language code (like en, cs, de or en-US, en-GB...) correctly
routes.MapRoute("Localization", "{lang}/{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new { lang = "[a-z]{2}(-[a-z]{2})" }
);