Areas and routing - c#

I'm quite stuck I might say dispite all other posts found on the site.
My solution has two areas Front and Back, and I don't want to use the default root controllers and views provided by default.
My FrontAreaRegistration.cs is like :
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Front",
"Front/{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
, new[] { "Show.Areas.Front.Controllers" }
);
}
My BackAreaRegistration.cs is like :
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Back_default",
"Back/{controller}/{action}/{id}",
new { controller = "Account", action = "LogOn", id = UrlParameter.Optional }
, new[] { "Show.Areas.Back.Controllers" }
);
}
And Global.asax like :
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
Getting folowing exception :
Multiple types were found that match the controller named 'Home'. This
can happen if the route that services this request
('{controller}/{action}/{id}') does not specify namespaces to search
for a controller that matches the request. If this is the case,
register this route by calling an overload of the 'MapRoute' method
that takes a 'namespaces' parameter.
The request for 'Home' has found the following matching controllers:
Show.Areas.Front.Controllers.HomeController
Show.Areas.Back.Controllers.HomeController
Problem is I can't reach the Home controller from Front area. Even if correct namespace added to context.MapRoute method overload ...
Any help will be appreciated.

The error is raised because you don't specify Area name in your request. Because of that "Default" route (from Global.asax) is matched for request and tries to search "Index" action of "Home" controller. As far as there two matches (for both areas) exceptions is thrown.
There are few ways to fix this. One possible is to modify Global.asax:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
new[] { "Show.Areas.Front.Controllers" }
).DataTokens.Add("Area", "Front");
But in this case "Default" route will work for Front area only.

Related

How to configure routes when using areas in asp.net mvc?

Scenario:
I have 3 Areas named- Albums, Singers , Music
Now each of these areas have controllers with same name. For instance every area has LoginController.
Now currently I am getting following exception
Multiple types were found that match the controller named 'Login'
This can happen if the route that services this request does not specify namespaces to search for a controller that matches the request.
If this is the case, register this route by calling an overload of the 'MapRoute' method that takes a 'namespaces' parameter.
This is auto generated Configuration by Visual Studio on Area Creation
public override string AreaName
{
get
{
return "Albums"
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Albums_Default"
"Client/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
This is my intial configuration in RoutesConfig.cs
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "Application_Name" }
);
Now how to configure the routes that without any modification in url, the desired view is rendered.
Please try this one :
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL
new { controller = "Home", action = "Index", id = "" }, // Defaults
new[]{"AreasDemoWeb.Controllers"} // Namespaces
);
}
Help Link 1
Help Link2

How To Create Custom Route in MVC

I have an Area named Admin with a model named CMSPage. My controller is named CMSPagesController. I would like to create a custom route so I can use simply Page instead of CMSPage, so I thought by creating the following custom route, it would work but nope:
routes.MapRoute(
"AdminPages",
"Admin/Pages/{action}/{id}",
new { controller = "CMSPages", action = "Index", id = UrlParameter.Optional }
);
Could someone please lead me in the right direction?
using System.Web.Mvc;
using System.Web.Routing;
namespace MvcApplication1
{
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Blog", // Route name
"Archive/{entryDate}", // URL with parameters
new { controller = "Archive", action = "Entry" } // Parameter defaults
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
}
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
}
}
}
The order of the routes that you add to the route table is important. Our new custom Blog route is added before the existing Default route. If you reversed the order, then the Default route always will get called instead of the custom route.
The custom Blog route matches any request that starts with /Archive/. So, it matches all of the following URLs:
/Archive/12-25-2009
/Archive/10-6-2004
/Archive/apple
The custom route maps the incoming request to a controller named Archive and invokes the Entry() action. When the Entry() method is called, the entry date is passed as a parameter named entryDate.
Oops on my part. I forgot that there was the area registration process that happens as well. The issue is that I want to access this controller from the area in which I created it (Admin). So, the custom route registration has to happen there. Not in my RouteConfig.cs (see below). Thanks for the response Neeraj, you're answer is not wrong, just not correct for my question which was in regards to an area.
using System.Web.Mvc;
namespace WebApplication1.Areas.Admin
{
public class AdminAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Admin";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
// This is where the custom route has to be registered for me to access
// it from my area.
context.MapRoute(
"Admin_pages",
"Admin/Pages/{action}/{id}",
new { action = "Index",
controller = "CMSPages",
id = UrlParameter.Optional }
);
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
}
}

Trying to hide to HomeController /Home from the URL

I was referencing this question to try and get this done, but it only works for my index method and I am not sure why.
My project has one area in it (if that is relevent) and I have about 5 different views that I want to hide /home/ in the url.
Code:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"JobResults", // Route name
"JobSearch/{title}-{id}", // URL with parameters
new { controller = "JobSearch", action = "Job" }, // Parameter defaults
new[] { "inkScroll.Web.Controllers" }
);
routes.MapRoute("home", "{action}",
new { controller = "Home", action = "index" });
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new
{
controller = "^(account|common|base|jobsearch)$", //every controller goes in here
action = "Index",
id = UrlParameter.Optional
},
new[] { "inkScroll.Web.Controllers" }
);
I am solving the same problem with the help of Attribute based Routing feature of ASP.NET MVC 5. Say, I have an action named ContactUs in my Home Controller as follows:
public ActionResult ContactUs()
{
return View();
}
I used to get Url for ContactUs as /Home/ContactUs. But, I wanted it to be simply /ContactUs. So, I am decorting the ContactUs action with Route Attribute as follows:
[Route("ContactUs")]
public ActionResult ContactUs()
{
}
So, this is working perfectly for me. Therefore, if you are using ASP.NET MVC 5, I would say, utilize this excellent feature of MVC5. It will not only save you from separating Route Logic and Actions, but also, it solves many problems very easily.
If ASP.NET MVC5 is not an option for you, or if you dont want to use Route Attribute on Action Methods, then, perhaps the following route can work: ( I did not test it though)
routes.MapRoute("Default", "",
new { controller = "Home", action = "index" });
This page contains helpful resource about Attribute Routing: http://blogs.msdn.com/b/webdev/archive/2013/10/17/attribute-routing-in-asp-net-mvc-5.aspx
Catch all wildcard route as the last one would work
routes.MapRoute("home2", "{*path}",
new { controller = "Home", action = "index" });

How to route request to www.MyDomain.com to specific controller class and method

In my MVC application, when user goes to www.MyDomain.com/Home, this request is processed in HomeController class Index method due to following routing entry in Global.asax
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
Let's say if user goes to www.MyDomain.com/SomeParameters, I want this request to be processed in MyController class Index method. An example for the parameters will be www.MyDomain.com/John. For this I have created following entry in Global.asax but it does not seem to get hit. Can anyone point out what I am doing wrong here?
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "MyController", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
The routing handles John as the controller, not the action. So in your example John is the controller and because you don't provide an action, it takes Index as the default action.
If you want www.MyDomain.com/John to be routed to controller MyController, action Index and a parameter that contains John, a solution could be to add the following route (before the default route):
routes.MapRoute(
name: "MyController",
url: "{myparameter}",
defaults: new { Controller = "MyController", Action = "Index" });
And the controller:
public ActionResult Index(string myparameter)
{
return View("whatever");
}
This will lead www.MyDomain.com/John to the Index action with myparameter = "John".
ps. In the example myparameter is mandatory.
In order to have www.MyDomain.com/SomeParameters you simply need to create a route where the Controller and the Action method are defaulted since they will not be provided in the URL.
Make sure the route definition only includes the someparameters and does not have anything else. This way you can just treat anything in the URL after / as a parameter.
routes.MapRoute(
name: "MyController",
url: "{someparameters}",
defaults: new { Controller = "MyController", Action = "Index" });
public ActionResult Index(string someparameters)
{
...
return View();
}

How can I implement "natural" url scheme routing tables in ASP.NET MVC

I would like to specify my routing tables such that they would feel much more "natural"
/Products
/Product/17
/Product/Edit/17
/Product/Create
Close to the defaults configuration but such that "Index" action would be mapped to the multiples form of the controller name and "Details" action would be mapped directly with an id of the item directly following the controller name.
I know I can achieve this by explicitly defining special routing mappings like this:
routes.MapRoute(
"ProductsList",
"Products",
new { controller = "Product", action = "Index" }
);
routes.MapRoute(
"ProductDetails",
"Product/{id}",
new { controller = "Product", action = "Details" }
);
/*
* Ditto for all other controllers
*/
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
The code above is way too verbose for my tastes and has the downside that each controller needs to be mentioned at least twice to prevasively apply this url pattern.
Is there some way to generalize this or am I bound to manual labour in this case?
You can try something like this:
routes.MapRoute(
"ProductsList",
"{pluralizedControllerName}",
new { controller = "Home", action = "Index" },
new { pluralizedControllerName = new PluralConstraint() }
);
routes.MapRoute(
"ProductDetails",
"{controller}/{id}",
new { controller = "Home", action = "Details" },
new { id = #"\d+" }
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
Notice the constraint in second route, it ensures that /Product/Create doesn't get picked by second route so that it gets mapped as third.
For route testing you can use routedebugger, and for writing unit test for routes try MvcContrib-TestHelper. You can get both with NuGet.
EDIT:
You can use this simple pluralizer and then implement something like this:
public class PluralConstraint : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
List<string> names = GetControllerNames();//get all controller names from executing assembly
names.ForEach(n => n.Pluralize(n));
return names.Contains(values[parameterName]);
}
}

Categories