I have a Contacts controller in the main/top area, and I have an area named "Contacts".
I get POST 404s to the Contacts controller if I register my areas before I register my top-level routes:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
ModelBinders.Binders.DefaultBinder = new NullStringBinder();
RouteConfig.RegisterRoutes(RouteTable.Routes);
}
And, if I register my areas after my routes, my 404s to the Contacts controller goes away, but my routes to the Contacts area are now 404s.
...lots of duplicate controller name questions logged, but I haven't found a specific scenario where the area is the same name as the controller.
...probably an easy fix. Would appreciate help. :-D
fwiw, I am registering my Contacts area with an explicit namespace:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "MyMvcApplication.Controllers" }
);
}
There are two things to consider
In Application_Start() method register areas first AreaRegistration.RegisterAllAreas();.
In case of conflicting name, use the namespaces in RouteConfig.cs file of App_Start folder as well as all the routes defined in routes (like ContactsAreaRegistration.cs)
To replicate your scenario, I created a sample application and able to access successfully both URLs given below:
http://localhost:1200/Contacts/Index
http://localhost:1200/Contacts/contacts/Index
The structure of my application looks like:
Here inside ContactsAreaRegistration.cs file we are having following code:
public class ContactsAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Contacts";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Contacts_default",
"Contacts/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "MvcApplication1.Areas.Contacts.Controllers" }
);
}
}
Hope it will help you. If you need I can send sample application code which I have created. Thanks.
For MVC5, I did what #Snesh did but that didn't fully work. It would only resolve the controllers in my area but not in the root of the project if they had the same name. I wound up having to specify the namespaces as parameters in both the RegisterArea method and the RegisterRoutes method in my RouteConfig.cs.
RouteConfig.cs
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
// This resolves to the Controllers folder at the root of the web project
namespaces: new [] { typeof(Controllers.HomeController).Namespace }
);
}
AreaRegistration.cs
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Handheld_default",
"Handheld/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional },
namespaces: new[] { typeof(Areas.Handheld.Controllers.HomeController).Namespace }
);
}
Related
I know how to create a URL friendly route and i also know how to remove index. But I'm wondering how do I combine the two together?
Using this tutorial https://www.jerriepelser.com/blog/generate-seo-friendly-urls-aspnet-mvc/ I was able to add the following code to allow for url friendly routes.
routes.Add("ProductDetails", new SeoFriendlyRoute("drink/{id}",
new RouteValueDictionary(new { controller = "Drink", action = "Index" }),
new MvcRouteHandler()));
So instead of my url being test.com/index/drink/1 it now becomes test.com/index/drink/coke
The next set of code I have is to remove the index from the url.
routes.MapRoute("DrinkRoute",
"drink/{id}",
new { controller = "Drink", action = "Index" });
This will succesfully convert test.com/index/drink/1 to test.com/drink/1
May I ask how do I combine the two together so that I can have a route that will lead me to the correct controller action and display test.com/drink/coke
RouteConfig
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
You can also achieve the same using attribute routing which would provide more control of the desired routes.
Reference Attribute Routing in ASP.NET MVC 5
First you would need to enable attribute routing by calling routes.MapMvcAttributeRoutes(); in your RouteConfig. Make sure it is registered before convention-based routes.
public class RouteConfig {
public static void RegisterRoutes(RouteCollection routes) {
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
//Attribute routes
routes.MapMvcAttributeRoutes();
//Default convention-based routes
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
With attribute routing enabled you can specify your routes by annotating your actions and controllers.
[RoutePrefix("drink")]
public class DrinkController : Controller {
[HttpGet]
[Route("{name}")] // GET drink/coke
public ActionResult Index(string name) {
//...use name to get model
return View();
}
//..
}
The above DrinkController.Index action is now mapped to GET drink/coke assuming test.com is the host of the controller as shown in your example.
Any controllers or actions not annotated by routing attributes will default back to the convention based routes (if any) registered in the routing table.
This means that you can have a mix of convention-based and attribute-based routes defined for your controllers.
Note however that once you use the attribute routes on a controller that you will have to use it on all its public actions.
If I understand you correctly, you can achieve desired behavior with RouteConfig.cs:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "DrinkRoute",
url: "drink/{id}",
defaults: new { controller = "Drink", action = "Index" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
In that case the url test.com/drink/coke will be hit with the controller DrinkController.cs and the action method Index. Id will be coke. Source code of this controller:
public class DrinkController : Controller
{
public ActionResult Index(string id)
{
return View();
}
}
You can remove the SEO Routes and give your action or controller full control:
public class DrinkssController : Controller
{
[Route("drink/{drinkName}")]
public ActionResult Index(string drinkName)
{
var model = _drinks.First(x => x.name == drinkName);
return View(model);
}
}
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
i tried to split my module in areas
my modules are
1. Login
2. User Admin
3. Master
i created the area and my first start up page is (area = login, controller = login, action = loginpage)
My code route config codes are
RouteConfig.cs
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Login", action = "Login", id = UrlParameter.Optional },
namespaces: new[] { "SRR.Areas.Login.Controllers" }
);
}
}
LoginAreaRegistration.cs
public override string AreaName
{
get
{
return "Login";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
//Trace.WriteLine("Login");
context.MapRoute(
"Login_default",
"{controller}/{action}/{id}",
new { controller = "Login", action = "Login", id = UrlParameter.Optional },
namespaces: new[] { "SRR.Areas.Login.Controllers" }
);
}
UserAdminAreaRegistration.cs
public class UserAdminAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "UserAdmin";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"UserAdmin_default",
"UserAdmin/{controller}/{action}/{id}",
new { controller = "Menu", action = "MenuPrivilages", id = UrlParameter.Optional },
namespaces: new[] { "SRR.Areas.UserAdmin.Controllers" }
);
}
}
Here my starting page login is coming fine but the useradmin module is views are not showing it through the error has "The resource cannot be found".
Thanks in advance
Login area registration missies the area specification in the pattern definition; change "{controller}/{action}/{id}" to "Login/{controller}/{action}/{id}"
What happens if your remove the namespaces constraints from the route registrations? Are the controllers (all of them Login and UserAdmin) in correct namespaces? I guess the Login controllers are showing because of the missing area specification as i mentioned above and the Login* controllers aren't in the correct namespaces.
You RegisterRoutes method misses a line before the default route registration:
AreaRegistration.RegisterAllAreas();
The issue that I believe is you have the controller 'login' and action method 'login' twice, one in area and other in root. So that the namespace must differ but you have the similar namespace for both the routes which is wrong. By default it is not necessary to specify the namespace for the default route since it'll map the root files. This might be the reason why the application could not find which log in to call.
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 }
);
}
}
}
For an ASP.NET MVC application, I have 2 controllers with the name Home. One of the controllers is in an Areas section, one is not. If someone goes to the base path /, I am trying to default to the controller in the Areas section. I am under the impression that this is possible. I have the following setup which I believe is supposed to make that happen -
When I go to /, I am still taken to the Controller in MVCArea01/Controllers/ and not MVCArea01/Areas/Admin/Controllers/.
(in case the code in the image is too small to see, here is the code for the method, RegisterRoutes)
public static void RegisterRoutes(RouteCollection routes)
{
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
new[] {"MVCAreas01.Areas.Admin.Controllers"} // I believe this code should cause "/" to go to the Areas section by default
);
}
What is the correct solution?
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new {
controller = "Home",
action = "Index",
id = UrlParameter.Optional,
area = "Admin"
}
}
#ABogus
I modified the AdminAreaRegistration.cs file. Refer the image below
Also I modified the Route.config as below.
I got the output as like this
You can download the sample project from https://www.dropbox.com/s/o8in2389e8aebak/SOMVC.zip
You should create additional route for your starting page, that will direct processing to the right controller:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Home_Default",
"",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new[] { "MVCAreas01.Areas.Admin.Controllers" });
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "MVCAreas01.Controllers" }
);
}