ASP.NET MVC Routing, Need help creating route - asp.net-mvc

My current Routing rules are
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
routes.MapRoute(
"Admin", // Route name
"Admin/{controller}/{action}/{id}", // URL with parameters
new { controller = "Admin", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
I have several controllers that can only be accessed by the Admin. Currently I have a menu at:
/Admin/Index
Which lists a bunch of action links. Right now clicking any of those links redirects like this example:
/News/Index
But I need it to be like:
/Admin/News/Index
This current setup sort of works, but links on my homepage are being caught by the wrong rule and are going to, for example /Admin/Article/1 when they should be just /Article/1
I've searched StackOverflow for the answer, and found some that come close - but I still don't understand routing well enough to make use of their answers. Any assistance is appreciated.
EDIT
Here are a collection of links from the homepage that are being caught by the routing rules incorrectly
<div id="menucontainer">
<ul id="menu">
<li><%: Html.ActionLink(" ", "About", "Home", null, new { ID = "AboutMHN" })%></li>
<li><%: Html.ActionLink(" ", "Products", "Home", null, new { ID = "Products" })%></li>
<li><%: Html.ActionLink(" ", "HubLocator", "Home", null, new { ID = "HubLocator" })%></li>
<li><%: Html.ActionLink(" ", "ResellerProgram", "Home", null, new { ID = "ResellerProgram" })%></li>
<li><%: Html.ActionLink(" ", "ResellerLogin", "Home", null, new { ID = "ResellerLogin" })%></li>
<li><%: Html.ActionLink(" ", "ContactUs", "Home", null, new { ID = "ContactUs" })%></li>
</ul>
</div>
Also, my Admin controller just has an index action. I have controllers for all of the other 'Admin' pages, for example my NewsController has actions for index, create, edit, delete, for listing all the news articles, and performing crud operations. Am I structuring this incorrectly?
My AdminController.cs
[Authorize(Roles = "Administrator")]
public class AdminController : Controller
{
//
// GET: /Admin/
public ActionResult Index()
{
return View();
}
}
The Admin/Index this returns contains a menu with ActionLinks just like
<li><%: Html.ActionLink("News Articles", "Index", "News") %></li>
My NewsController.cs has Actions for performing CRUD operations. I would like the url to be
Admin/News/Edit/5
Instead of
News/Edit/5

Flip the two:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Admin", // Route name
"Admin/{controller}/{action}/{id}", // URL with parameters
new { controller = "Admin", 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
);
If that doesn't work, add the code for the News menu links to your question.

The mapping is from top to bottom, the first route that can apply will be used. In your case you have Admin route under Default. Since Default can be used it will, therefore you should place Admin route above Default. The problem with that is that all will use that route. You need to be a bit more specific, perhaps you should remove {controller} so that only Admin actions will use that route. Need more info to better advise.

I needed to use Areas.
See: http://elegantcode.com/2010/03/13/asp-net-mvc-2-areas/
I created a new Area called Admin, renamed my AdminController.cs to MenuController.cs and placed all of the required controllers and views inside of the Admin area folder. Inside the Admin area folder there is a file called AdminAreaRegistration.cs which contains
public class AdminAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Admin";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
new { controller= "Menu", action = "Index", id = UrlParameter.Optional }
);
}
}
I had to add in the controller = "Menu" so that when you navigate to /Admin it will take you to /Admin/Menu/Index by default. Now any of my controllers in the area folder are accessible like /Admin/News/Edit/5 and so forth. Thanks for your attempts, I should have been more clear that I am an absolute MVC noob and didn't know about Areas to begin with.

Related

Using routes.MapPath to accommodate missing URL parameter

I have an MVC website which used to use URLs in the standard format of: Controller/Action.
Recently, I have changed it to: Site/Controller/Action.
The problem is, there are several links to my site out there which follow the old format, and I want to redirect them accordingly.
for example: mydomain.com/Home/CustomerSearch now should go to mydomain.com/Online/Home/CustomerSearch
whereas: mydomain.com/AffiliatesHome/CustomerSearch now should go to mydomain.com/Affiliate/AffiliatesHome/CustomerSearch
How can I get it to handle the redirecting by putting in the extra routing, depending on the link they came in by?
The current routing I am using is:
routes.MapRoute(
"Default", // Route name
"{site}/{controller}/{action}/{id}",
new {site="IS", controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Since I do not really see an schema in your old to new URL mapping I would suggest to add routes that match the old Controller/Action Schema and map them to the new Site/Controller/Action route schema.
So you could add the following routes
routes.MapRoute(
"LegacyHome",
"Home/{action}/{id}",
new { site="Online", controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
"LegacyAffiliates",
"AffiliatesHome/{action}/{id}",
new { site="Affiliate", controller = "AffiliatesHome", action = "Index", id = UrlParameter.Optional }
);
From an SEO standpoint this is not ideal because you have different URLs for the same page. A permanent redirect via status code 301 and the new URL passed in the location is better suited.
You could build a redirect controller and use the legacy routes to map legacy URLs to the redirect controller somehow like this
routes.MapRoute(
"LegacyHome",
"Home/{newAction}/{id}",
new { controller = "Redirect", action = "Redirect", newSite = "Online", newController="Home", newAction = "Index", id = UrlParameter.Optional }
);
Code of the redirect controller
public class RedirectController : Controller
{
public ActionResult Redirect(string newSite, string newController, string newAction)
{
var routeValues = new RouteValueDictionary(
new
{
site = newSite,
controller = newController,
action = newAction
});
if (RouteData.Values["id"] != null)
{
routeValues.Add("id", RouteData.Values["id"]);
}
return RedirectToRoutePermanent(routeValues);
}
}

Generate semantic URL with asp.net mvc4 ActionLink in Razor views

I have a below setup in the controller for Public facing web page
Company -> About -> Partners ( which i want to be accessed as Company/About/Partners )
Action Method
public about(string category)
{
ViewBag.Category = category;
return View();
}
Generation of the link is done as below which is giving me the wrong URL
#Html.ActionLink("Partners & Investors", "About", "Company",new { Category = "Partners" },null)
Wrong Url
Company/About?Category=Partners%20and%20Investors
So the question is how does one generate the correct url that i wanted. What should i do ?
Urls will be generated automatically when you create new route and put it on correct position.
Add
Something like this:
routes.MapRoute(
"Category",
"Company/About/{category}",
new { controller = "Company", action = "About", category = "default" }
);
// default
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Also look at this link: Advanced Routing

How to control routing values

Maybe I don't understand real purpose of asp mvc routing.
I created an application and now I need to fix my url's a to be more understandable.
For example I have area Cities with controller Home and action Index.
So here I need url like: localhost/London but with current routing I get localhost/cityPage/Home.
My question is can I somehow pass parameter like city name and make URL like I want?
This is my current default routing in Global.asax
routes.MapRoute(
"Default",
"{area}/{controller}/{action}/{id}",
new { area = "CityPage", controller = "Home", action = "Index", id = "" },
new string[] { "MyProject.Areas.Cities.Controllers" }).DataTokens.Add("area", "Cities");
New routing:
routes.MapRoute(null,
"CityPage/{cityName}",
new
{
area = "CityPage",
controller = "Home",
action = "Index"
}
);
routes.MapRoute(
"Default",
"{area}/{controller}/{action}/{id}",
new { area = "CityPage", controller = "Home", action = "Index", id = "" },
new string[] { "MyProject.WebUI.Areas.CityPage.Controllers" }).DataTokens.Add("area", "CityPage");
Example of link that I click
#Html.ActionLink("City London", "Index", "Home", new { cityName = "London" }, null)
In order to route the URL localhost/London to the Index action on the HomeController of the Cities area, you need a route like this:
routes.MapRoute(null,
"{id}",
new
{
area = "Cities", controller = "Home", action = "Index"
}
);
Be sure this route is declared before the "Default" route in your CitiesAreaRegistration.cs class.
However if you have a lot of other routes in your application, adding a general route like this can play havoc with other routes in the app. I suggest adding a URL prefix to separate this route from others in your application:
routes.MapRoute(null,
"cities/{id}",
new
{
area = "Cities", controller = "Home", action = "Index"
}
);
This will make your URL look like localhost/cities/London. Is that acceptable?
Update 1
Unless you completely remove your "Default" route definition, you will actually have multiple INBOUND routes that map to this action. You would have localhost/cities/London, localhost/cityPage/Home, localhost/cityPage/Home/Index, and localhost/cityPage/Home/Index/London all resolving to that action. However when MVC chooses to generate an OUTBOUND route, it will choose the first one -- localhost/cities/London.
Update 2
If you want your route parameter to be cityName, you would do this:
routes.MapRoute(null,
"cities/{cityName}",
new
{
area = "Cities", controller = "Home", action = "Index"
}
);
However you would then have to change the Index action on your Cities area's HomeController to have this signature:
public ActionResult Index(string cityName)
By changing the argument from id to cityName, you are telling MVC to pass this URL paramter / route segment to the action method.
Update 3
Is the name of your area "Cities" or "CityPage"? From previous code it looked like the name of your area was Cities.
If it is CitiesPage, try this for your action method:
#Html.ActionLink("City London", "Index", "Home",
new { area = "CityPage", cityName = "London" })
Final Answer
I just reproduced this in an MVC3 project, and it is working as expected:
Created a new area named "CityPage"
Added a HomeController with an Index action to the CityPage area
Added an Index view to the CityPage/Views/Home folder.
CityPageAreaRegistration.cs:
public class CityPageAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "CityPage";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(null,
"CityPage/{cityName}",
new { area = "CityPage", controller = "Home", action = "Index" }
);
//context.MapRoute(
// "CityPage_default",
// "CityPage/{controller}/{action}/{id}",
// new { action = "Index", id = UrlParameter.Optional }
//);
}
}
HomeController.cs:
public class HomeController : Controller
{
//
// GET: /CityPage/Home/
public ActionResult Index(string cityName)
{
return View();
}
}
Index.cshtml:
#{
ViewBag.Title = "Index";
}
<h2>
Index</h2>
#Html.ActionLink("City London", "Index", "Home",
new { area = "CityPage", cityName = "London" }, null)
Finally, here is the link generated by the action link:
City London
yes you can do this way but you have to do following thing
Make sure your route must register before generic route.
Get Information about RouteConstraint
http://www.asp.net/mvc/tutorials/controllers-and-routing/creating-a-route-constraint-cs
http://www.asp.net/mvc/tutorials/controllers-and-routing/creating-a-custom-route-constraint-cs
Just for example Try this way check your required url localhost/London
routes.MapRoute(
"Default",
"{id}",
new { area = "CityPage", controller = "Home", action = "Index", id = "" },
new string[] { "MyProject.Areas.Cities.Controllers" }).DataTokens.Add("area", "Cities");

Setting up Index as the default route for a controller

I have a url
http://www.roadkillwiki.org/Page/Index/documentation
which I want to turn into
http://www.roadkillwiki.org/Page/documentation
That could also be something like http://www.roadkillwiki.org/Page/my-url-with-spaces - the parameter is a string. The route setup I've tried is:
routes.MapRoute(
"ControllerDefault",
"{controller}/{id}",
new { controller = "Page", action = "Index", id = UrlParameter.Optional }
);
However this is interfering with the default "id" route that MVC projects come with. Is there any way of achieving this?
You don't need to lose the default route. The key to avoiding your routes interfere with each other is to order them so the more specific rules precede the less specific ones. For example:
// Your specialized route
routes.MapRoute(
"Page",
"Page/{slug}",
new { controller = "Page", action = "Index" }
);
// Default MVC route (fallback)
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
Then your PageController would look like this:
using System.Web.Mvc;
public class PageController : Controller
{
public string Index(string slug)
{
// find page by slug
}
}
That said, I would strongly advice you to do this instead:
// Your specialized route
routes.MapRoute(
"Page",
"Page/{id}/{slug}",
new { controller = "Page", action = "Index", slug = UrlParameter.Optional }
);
// MVC's default route (fallback)
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
And your PageController:
using System.Web.Mvc;
public class PageController : Controller
{
public string Index(int id)
{
// find page by ID
}
}
By including the page ID either at the beginning of your URL (like StackOverflow does) or at the end, you can then just ignore the slug, and instead retrieve your pages by ID. This will save you a ton of headaches if your users change the page name. I have gone through this and it's painful; you basically have to keep a record of all names your pages have had in the past, just so your visitors/search engines don't get a 404 every time a page is renamed.
Hope this helps.
If you don't need a default route that came with project template you can set up one like this:
routes.MapRoute(
"ControllerDefault",
"{controller}/{pagename}",
new { controller = "Page", action = "Index" }
);
And than in your controller you would have an action:
public ActionResult Index(string pagename)
{
//do something
}

ASP.Net MVC Outbound Route Matching Problem When Using ActionLink

Hoping for some help after reading into MVC routing and not coming up with the answer myself.
I have the following routes registered:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
null,
"YourFeedback/Article/{resourceId}",
new { controller = "YourFeedback", action = "Index", contentTypeId = new Guid(ConfigurationManager.AppSettings["ArticleLibraryId"]) });
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
}
I have the following ActionLink in an aspx view:
<%=Html.ActionLink("Your Feedback", "Article", "YourFeedback", new
{
resourceId = Model.ContentId.ResourceId
}, new { #class = "yourFeedback" })%>
My understanding of MVC routing is that this would render a anchor link with href of "/YourFeedback/Article/101" where 101 comes from Model.ContentId.ResourceId.
Yet the anchor link href is rendered as "YourFeedback/Article/resourceId=101".
Any ideas where I'm going wrong?
Thanks in advance.
This is because your actionlink will match the second route and not the first. The reason is that you have some strange default values in your first route. You have set the controller to "YourFeedback" and the action to "Index". That means that you will have to set that in your actionlink as well if you want to match that route.
To match the route you will have to use this actionlink:
<%=Html.ActionLink("Your Feedback", "Index", "YourFeedback", new
{
resourceId = Model.ContentId.ResourceId
}, new { #class = "yourFeedback" })%>
Or change the route.

Resources