How to omit controller name for Home views - c#

Let's say I have this structure:
Home/
Index
About
Project/
Index
Details
How can I omit the controller name for Home views?
I want to write {root}/About instead of {root}/Home/About.
I also want {root}/Project/Details/2 to work.
Here is what I tried in RegisterRoutes:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "DefaultRoute",
url: "{controller}/{action}/{id}",
defaults: new
{
controller = "Home",
action = "Index",
id = UrlParameter.Optional
}
);
routes.MapRoute(
name: "HomeRoute",
url: "{action}",
defaults: new
{
controller = "Home",
action = "Index"
}
);
Edit: I also tried swapping the order of my MapRoute calls but it still doesn't work.
What I need is:
{root}/Home/Index > HomeController.Index
{root}/Home > HomeController.Index
{root} > HomeController.Index
{root}/Home/About > HomeController.About
{root}/About > HomeController.About
{root}/Project/Index > ProjectController.Index
{root}/Project > ProjectController.Index
{root}/Project/Details/12 > ProjectController.Details

Just change the order of your MapRoute calls:
routes.MapRoute(
name: "HomeRoute",
url: "{action}",
defaults: new { controller = "Home", action = "Index" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
The 'Default' route has to be defined last, otherwise it matches all Url patterns and no further routes are evaluated.
Update:
As per your edit, since you want to preserve the 'controller-name-only' route as well. Try this:
public class ActionExistsConstraint : IRouteConstraint
{
private readonly Type _controllerType;
public ActionExistsConstraint(Type controllerType)
{
this._controllerType = controllerType;
}
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
var actionName = values["action"] as string;
if (actionName == null || _controllerType == null || _controllerType.GetMethod(actionName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.IgnoreCase) == null)
return false;
return true;
}
}
Then:
routes.MapRoute(
name: "HomeRoute",
url: "{action}",
defaults: new { controller = "Home", action = "Index" },
constraints: new { exists = new ActionExistsConstraint(typeof(HomeController)) }
);
See MSDN

Related

ASP.NET MVC 5 Traditional Routing

When I debug it, the Product and Subcategory link works fine, however the Category shows me the list but when I click on one of them to show me the products inside each one, does not display anything.
Here is my ProductsController.cs.
public ActionResult Index(string category, string subcategory, string search, string sortBy, int? page){... }
On the RouteConfig.cs I have:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "ProductsCreate",
url: "Products/Create",
defaults: new { controller = "Products", action = "Create" }
);
routes.MapRoute(
name: "ProductsbySubCategorybyPage",
url: "Products/{subcategory}/Page{page}",
defaults: new { controller = "Products", action = "Index" }
);
routes.MapRoute(
name: "ProductsbyCategorybyPage",
url: "Products/{category}/Page{page}",
defaults: new { controller = "Products", action = "Index" }
);
routes.MapRoute(
name: "ProductsbyPage",
url: "Products/Page{page}",
defaults: new { controller = "Products", action = "Index" }
);
routes.MapRoute(
name: "ProductsbySubCategory",
url: "Products/{subcategory}",
defaults: new { controller = "Products", action = "Index" }
);
routes.MapRoute(
name: "ProductsbyCategory",
url: "Products/{category}",
defaults: new { controller = "Products", action = "Index" }
);
routes.MapRoute(
name: "ProductsIndex",
url: "Products",
defaults: new { controller = "Products", action = "Index" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Your ProductsbyCategorybyPage is overwritten by ProductsbySubCategorybyPage.
When ASP.NET is trying to parse the incoming URL, it will stop with the find match, and URL like Products/A/Page3 will be passed through the ProductsbySubCategorybyPage route. Routing module does not know what do you prefer A to be, subcategory or category. You need to refactor your RegisterRoutes method to use unique route masks. Like Products/SubCategory/{subcategory} and Products/Category/{category} for example.

Route Configuration in MVC

The current Route Config for me is this, which I think is the default one
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
When I write
www.mypage.com
www.mypage.com/home
I get the same page
How Can I make it so that they are two individual pages
www.mypage.com
is the homepage, and
www.mypage.com/home
is another page
www.mypage.com can be handler by a root controller and all the other routes will be handled by the default route.
routes.MapRoute(
name: "Root",
url: "",
defaults: new {controller = "Root", action = "Index"}
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { action = "Index", id = UrlParameter.Optional }
);
the explicit defaults allow for the behavior you are currently seeing.
You will still need to create a controller to handle your root site calls
public class RootController : Controller {
public ActionResult Index() {
return View();
}
}
And don't forget to create the related View for your controller.
No need to create a new controller. you can use the same home controller. In Home Controller, create 2 actions - Default and Index. In the routeconfig, use -
routes.MapRoute(
name: "RootDef",
url: "",
defaults: new { controller = "Home", action = "Default", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

Custom Url Routing

For www.demo.com/city/hotel-in-city
routes.MapRoute(
name: "Search",
url: "{city}/{slug}",
defaults: new { controller = "Demo", action = "Index", city = UrlParameter.Optional}
);
For default
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
But when I call the index method of home controller www.demo.com/home/index it points to 1st route(index method of default controller).
How to handle default route ?
The problem is that your "Search" route captures basically everything. One way of handling this is to create more-specific routes for the home controller, and put those first:
routes.MapRoute(
name: "Home1",
url: "/",
defaults: new { action = "Index", controller = "Home" }
);
routes.MapRoute(
name: "Home2",
url: "Home/{action}/{id}",
defaults: new { id = UrlParameter.Optional, action = "Index", controller = "Home" }
);
routes.MapRoute(
name: "Search",
url: "{city}/{slug}",
defaults: new { controller = "Demo", action = "Index" }
);
This will filter out any URL with "Home" as the first parameter, and allow everything else through to the search.
If you have a lot of controllers, the above approach may be inconvenient. In that case, you could consider using a custom constraint to filter out either the default route, or the "Search" route, whichever one you decide to put first in the route config.
For example, the following constraint declares the match invalid, in case the routing engine has attempted to assign "Home" to the "city" parameter. You can modify this as needed, to check against all your controllers, or alternately, against a cached list of available city names:
public class SearchRouteConstraint : IRouteConstraint
{
private const string ControllerName = "Home";
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
return String.Compare(values["city"].ToString(), ControllerName, true) != 0;
}
}
This will allow URLs starting with "/Home" through to the default route:
routes.MapRoute(
name: "Search",
url: "{city}/{slug}",
defaults: new { controller = "Demo", action = "Index" },
constraints: new { city = new SearchRouteConstraint() }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { id = UrlParameter.Optional, action = "Index", controller = "Home" }
);

How to convert query string parameters to route in asp.net mvc 4

I have a blogging system that I'm building and I can't seem to get ASP.NET MVC to understand my route.
the route I need is /blogs/student/firstname-lastname so /blogs/student/john-doe, which routes to a blogs area, student controller's index action, which takes a string name parameter.
Here is my route
routes.MapRoute(
name: "StudentBlogs",
url: "blogs/student/{name}",
defaults: new { controller = "Student", action="Index"}
);
My controller action
public ActionResult Index(string name)
{
string[] nameparts = name.Split(new char[]{'-'});
string firstName = nameparts[0];
string lastName = nameparts[1];
if (nameparts.Length == 2 && name != null)
{
// load students blog from database
}
return RedirectToAction("Index", "Index", new { area = "Blogs" });
}
But it won't seem to resolve...it works fine with /blogs/student/?name=firstname-lastname, but not using the route I want, which is /blogs/student/firstname-lastname. Any advice on how to fix this would be greatly appreciated.
My RouteConfig
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "StudentBlogs",
url: "blogs/student/{name}",
defaults: new { controller = "Student", action = "Index"},
constraints: new { name = #"[a-zA-Z-]+" },
namespaces: new string[] { "IAUCollege.Areas.Blogs.Controllers" }
);
routes.MapRoute(
name: "Sitemap",
url :"sitemap.xml",
defaults: new { controller = "XmlSiteMap", action = "Index", page = 0}
);
//CmsRoute is moved to Gloabal.asax
// campus maps route
routes.MapRoute(
name: "CampusMaps",
url: "locations/campusmaps",
defaults: new { controller = "CampusMaps", action = "Index", id = UrlParameter.Optional }
);
// core route
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
// error routes
routes.MapRoute(
name: "Error",
url: "Error/{status}",
defaults: new { controller = "Error", action = "Error404", status = UrlParameter.Optional }
);
// Add our route registration for MvcSiteMapProvider sitemaps
MvcSiteMapProvider.Web.Mvc.XmlSiteMapController.RegisterRoutes(routes);
}
}
You have to declare custom routes before the default routes. Otherwise it will be mapping to {controller}/{action}/{id}.
Global.asax typically looks like this:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
}
If you created an Area named Blogs, there is a corresponding BlogsAreaRegistration.cs file that looks like this:
public class BlogsAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Blogs";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Admin_default",
"Blogs/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
}
Hyphens are sometimes treated like forward slashes in routes. When you are using the route blogs/students/john-doe, my guess is that it is matching the Area pattern above using blogs/students/john/doe, which would result in a 404. Add your custom route to the BlogsAreaRegistration.cs file above the default routes.
Try adding the parameter to the route:
routes.MapRoute(
name: "StudentBlogs",
url: "blogs/student/{name}",
defaults: new { controller = "Student", action="Index", name = UrlParameter.Optional}
);
Try adding a constraint for the name parameter:
routes.MapRoute(
name: "StudentBlogs",
url: "blogs/student/{name}",
defaults: new { controller = "Student", action="Index" },
constraints: new { name = #"[a-zA-Z-]+" }
);
Dashes are a bit weird in MVC at times.. because they are used to resolve underscores. I will remove this answer if this doesn't work (although.. it should).
This has the added benefit of failing to match the route if a URL such as /blogs/student/12387 is used.
EDIT:
If you have controllers with the same name.. you need to include namespaces in both of your routes in each area. It doesn't matter where the controllers are.. even if in separate areas.
Try adding the appropriate namespace to each of the routes that deal with the Student controller. Somewhat like this:
routes.MapRoute(
name: "StudentBlogs",
url: "blogs/student/{name}",
defaults: new { controller = "Student", action="Index" },
namespaces: new string[] { "Website.Areas.Blogs.Controllers" }
);
..and perhaps Website.Areas.Admin.Controllers for the one in the admin area.

Set custom parameter in Route

I have 2 routes
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Plugin",
url: "{pluginName}/{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
I would like to use Html.Action helper and set "pluginName" parameter of my second Route.
I am try to use next code
#Html.Action("Index","Person",new RouteValueDictionary { { "pluginName", "myPlugin" } });
and to get link like
http://mydomain/myplugin/Person/index
but I've getting
http://mydomain/Person/index?pluginName="myPlugin"
How can I get first link pattern?
Register your more specific route first. The routing engine evaluates routes in the order you register them. So if you have a fairly generic route registered early on (which you do), the routing engine will use it and append other values as QueryString parameters (which your seeing).
Try this:
routes.MapRoute(
name: "Plugin",
url: "{pluginName}/{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

Categories

Resources