Routing Issue With Areas - asp.net-mvc

I'm having an issue with routing and areas as the title says. I have ana areas section in my project that just has one area in it. It has a Policy controller in there. Outside in the project there is a controller's folder with a LoginController.
When I try to got to the URL "BoB/Login/ChangeSection" (BoB is project name, Login is controller, ChangeSection is action) it gets sent to "BoB/Policy/Login". This means the Area registration inside the Policy area is grabbing the request and putting the Policy prefix in front when it shouldn't be.
Here is my project RouteConfig
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "BoBHome", action = "Index", id = UrlParameter.Optional },
namespaces: new string[] { "BoB.Controllers" }
);
and here is the Area registration
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
name: "BoBPolicy_default",
url: "Policy/{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new string[] { "BoB.Areas.BoBPolicy.Controllers" }
);
}
I was under the impression the namespaces would keep this from happening, but it obviously is not. Any help is appreciated.
Some additional info:
This comes from another project that is not MVC so the Redirect looks like this:
Response.Redirect("/BoB/BoBLogin/ChangeSection?controller=PolicyOverview");

I think your issue is similar to non area route issue, which requires usage of area parameter to prevent area URL prefix inserted when using default route:
public override void RegisterArea(AreaRegistrationContext context)
{
// set area parameter with area name
context.MapRoute(
name: "BoBPolicy_default",
url: "Policy/{controller}/{action}/{id}",
// add area parameter here
defaults: new { area = "Policy", controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new string[] { "BoB.Areas.BoBPolicy.Controllers" }
);
}
NB: Since area route registration always placed on top of default route (read this answer for reasons behind it), it is possible to have routing engine incorrectly picking up default route request into area route when area route constraint(s) not specified.
Related:
MVC5 Routing Go to specific Areas view when root url of site is entered

Related

MVC routes with static Prefix

I have two routes in my routeConfig files as follow.
Route with admin prefix which handles request for admin part
default Route without a prefix, for which I have added a datatoken to map routes in candidate Area
routes.MapRoute(
name: "admin",
url: "Admin/{controller}/{action}/{id}",
defaults: new { controller = "Account", action = "Login", id = UrlParameter.Optional },
namespaces: new[] { "abc.namespace1" }
);
routes.MapRoute(
name: "default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Account", action = "Login", id = UrlParameter.Optional },
namespaces: new[] { "abc.namespace2" }
).DataTokens.Add("area", "Candidate");
But the problem is when i type in a url localhost/MyApp/Admin/Home/Index
it is hitting the controller in abc.namespace1 (which is expected) and localhost/MyApp/Home/Index also hitting Home controller inside abc.namespace1 instead of HomeController inside abc.namespace2 in candidate Area.
What i want to do here is handle all routes with Admin prefix with controllers inside abc.namespace1 and all routes without any prefix with controllers inside abc.namespace2 which is my candiate Area.
regards
I believe this might have something to do with the way you have specified your namespaces. The namespace must be for where the controller classes reside.
The pattern is typically <namespace of area>.<area name>.<controller namespace>
For example, in a project with an area named "Admin", the namespace must be:
"MvcMusicStore.Areas.Admin.Controllers"
In my experience, the conventions for how areas are set up are pretty strict. You should not set up the route in an AreaRegistration rather than the root of your project in order to get it to work.
public class CandidateAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Candidate";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Candidate_default",
"{controller}/{action}/{id}",
new { controller = "Account", action = "Login", id = UrlParameter.Optional },
new string[] { "<project name>.Areas.Candidate.Controllers" }
);
}
}
Areas are convention-based. If you deviate too far from the anticipated conventions, they simply don't function.

Access one web project from another web project asp.net mvc

Problem
In asp.net mvc i have two mvc application in one solution one is website and second is admin panel. And I I have created one folder that name is administrator inside of website project and paste admin project inside of website project now I want access admin section like way :
http://localhost/website/admin
As like nopcommerce but I'm not getting how nopcommerce configured this thing in their project.
Help me out
As others have stated, it may be best to use ares in order to simplify the project, but if you want to keep them separated, I think the problem you are having is updating your routing.
By default, MVC applications have the following routing config (found in the Globals.asax.cs file):
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
What you will need to do is look at the controller you're trying to wire up, and put in a route for that controller. For the sake of an example, I will assume your controller is called "AdminController":
routes.MapRoute(
name: "AdminController",
routeTemplate: "website/admin/{action}",
defaults: new { controller = "Admin", action = "Index"}
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
This example shows you how to map the desired route -- http://localhost/website/admin -- to the "Index" action on the "AdminController" object.
For more in-depth ASP.Net routing examples, you can look at the documentation here
Update: After looking at the example library in question (NopCommerce), it would appear they are using an explicit area registration. This is found in 'src/Presentation/Administration/AdminAreaRegistration.cs' :
using System.Web.Mvc;
namespace Nop.Admin
{
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 = "Home", action = "Index", area = "Admin", id = "" },
new[] { "Nop.Admin.Controllers" }
);
}
}
}
Hopefully this gives you a better idea of how this is done.
This tutorial has cleared my confusion that how to configure more then one project in asp.net mvc as area.
http://nileshhirapra.blogspot.no/2012/02/aspnet-mvc-pluggable-application.html?m=1

MVC5 Custom Route to Remove Controller Name from Area

So far I can't make this work and I need some assistance please. I have a basic MVC 5 site, and I have added an area called Administration. For the life of me, I can't figure out how to set a default controller/action for an area, properly.
In my site, I have an area named Admin, a controller named Admin (with Index method and view), and this is the area registration:
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
name: "Admin_base",
url: "Admin",
defaults: new { area = "Admin", controller = "Admin", action = "Index", id = UrlParameter.Optional }
);
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
The first MapRoute allows me to browse to http://myapplication/Admin and it displays a view that I set (Admin/Index) and the URL stays http://myapplication/Admin (which is what I want). Now, by adding this, it breaks any further routing to a controller. So when I attempt to navigate to the Menu controller in the Admin area, it fails.
Is there a correct way to do this?
i.e. I need to make http://myapplication/Admin/Menu/Create route properly, but also need to retain the default Controller/Action for the area.
You should just be able to combine them into one:
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
defaults: new { area = "Admin",
controller = "Admin",
action = "Index",
id = UrlParameter.Optional }
);
By assigning defaults, you should be able to call /Admin/ and the rest of the parameters are set to the defaults.
If you are using the same controller name for Area and default one(For eg: HomeController). Use the namespaces for that
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
new {
area = "Admin",
controller = "Home",
action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "{{Namespace}}.Areas.Admin.Controllers" }
);
for default one
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home",
action = "Index",
id = UrlParameter.Optional },
namespaces: new[] { "{{Namespace}}.Controllers" }
);

How to route this in ASP MVC

This is my first ASP MVC project so I'm not sure how to do this.
I have a section called Admin, which has an Admin controller. I'm using this for just an index page.
In the Admin section, there are different sections. Let's say Company and Line Of Business
I want to handle everything for those in their own CompanyController and LineOfBusinessController
I want the routes to be prefixed with Admin though ie. Admin/Company, Admin/Company/Add
I have achieved this by adding a route before the Default route that is this
routes.MapRoute(
name: "Admin",
url: "Admin/{controller}/{action}/{id}",
defaults: new { controller = "Admin", action = "Index", id = UrlParameter.Optional }
);
The problem is now all my routes choose this one over the default, meaning everything else becomes Admin/Section ie Admin/Home etc.....
I tried using Html.RouteLink instead of ActionLink and the URL's were formatted correctly, but when I go to Admin/Company it can't find because it assumes Company is in AdminController
How can I route this properly?
EDIT
Here are my routes, and then my links
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
routes.MapRoute(
name: "Admin",
url: "Admin/{controller}/{action}/{id}",
defaults: new { controller = "Admin", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Links
<li>#Html.ActionLink("Home", "Index", new { controller = "Home" }, ViewBag.SelectedNav == "Home" ? new { #class = "active" } : null)</li>
The link ends up /Admin/Home
UPDATE
Did not mark an answer here as I ended up exploring, and ultimately using Areas. It was suggested in the one answer, but the rest of the answer is not correct so I did not want to mislead anyone. Thanks for the Area suggestion however
Have the generic routing below your specific one. The order of routing definition is important. When MVC finds a matching route for a request, it won't process the rest.
routes.MapRoute(
name: "Admin",
url: "Admin/{controller}/{action}/{id}",
defaults: new { controller = "Admin", action = "Index",
id = UrlParameter.Optional }
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index",
id = UrlParameter.Optional } // Parameter defaults
);
Also it is better for your to use Areas in this scenario. It is a better approach when you want to structure your app in to different sections like Admin / Normal user etc..
Since I don't know what the link behavior should be, the best thing I can suggest is to debug your routes and see which route is handling which URL's.
1) Go into Visual Studio and install the RouteDebugger
PM> Install-Package routedebugger
2) Add some code to your global file
protected void Application_Start(object sender, EventArgs e)
{
RegisterRoutes(RouteTable.Routes);
RouteDebug.RouteDebugger.RewriteRoutesForTesting(RouteTable.Routes);
}
3) Run your site and request your questionable links.
4) Review your results and modify accordingly
Edit: it appears as though RouteDebugger v2 is now RouteMagic
PM> Install-Package RouteMagic
And you can find the source code on github

ASP.NET MVC3 Area controller accessible from global routes?

Perhaps I do not understand correctly how MVC Areas work, but this has got me a little confused.
Add an Area called "MyArea" using right-click "Add Area" in Visual Studio on the MVC3 project
Create a controller for MyArea: "AnArea" with matching view in the MyArea area.
Add "controller = "AnArea" to context.MapRoute's defaults parameter in MyAreaAreaRegistration.RegisterArea method.
So at this point if you start the application and navigate to /MyArea/ it should load the AnArea controller with it's matching view. If you navigate to /MyArea/AnArea, it will show the same result.
But, if you navigate to /AnArea/, the controller is still found and the following error message is displayed:
The view 'Index' or its master was not found or no view engine supports the searched locations. The following locations were searched:
~/Views/anarea/Index.aspx
~/Views/anarea/Index.ascx
~/Views/Shared/Index.aspx
~/Views/Shared/Index.ascx
~/Views/anarea/Index.cshtml
~/Views/anarea/Index.vbhtml
~/Views/Shared/Index.cshtml
~/Views/Shared/Index.vbhtml
Is this the correct behaviour? I would have thought an area's controller could only be accessed via it's own area and not globally.
Whenever I create an project with areas, I change my Default route as follows:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // defaults
null, // constraints
new string[] { "MyApplication.Controllers" } // namespaces
);
The final parameter limits the default route to the controllers in the MyApplication.Controllers namespace. This insures that the Default route is limited to actions outside of any areas.
UPDATE
After a deep dive into the code, I discovered where the issue arises, and have a solution. Change your Default route to the following:
routes.Add(
"Default",
new Route("{controller}/{action}/{id}",
new RouteValueDictionary(
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
),
null,
new RouteValueDictionary(
new {
Namespaces = new string[] { "MyApplication.Controllers" },
UseNamespaceFallback = false
}
),
new MvcRouteHandler()
)
);
The key is in adding the UseNamespaceFallback token. This will prevent the Default route from looking into any other namespaces.
This is unexpected behavior, and it was a problem I was unaware of which affects a project I am working on. I will list it as an issue at aspnet.codeplex.com. I would not call this a bug, but the behavior definitely appears to breach the convetions for MVC routing.
You have to apply a namespace restriction in both area and general route.
In global.asax.cs you should edit RegisterRoutes method just like this
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new string[] { "MyProject.Controllers" }
);
}
That will restrict "//" only to the namespace "MyProject.Controllers"
But also you´ll have to apply the namespace restriction to the Area to restrict "//" only to the namespace "MyProject.Areas.MyArea.Controllers"
For that you´ll have to edit "RegisterArea" method of "MyAreaAreaRegistration.cs" like below ("MyAreaRegistration.cs" is located at "/MyProject/Areas/MyArea" folder ) :
//Some default code stuff
...
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"MyArea_default",
"MyArea/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional },
new string[] { "MyProject.Areas.MyArea.Controllers" }
);
}
Hope it helps!!
You seem to be navigating to /AnArea whereas your area is called MyArea so you should navigate to /MyArea/. Here's how the area route registration looks like:
context.MapRoute(
"MyArea_default",
"MyArea/{controller}/{action}/{id}",
new { controller = "AnArea", action = "Index", id = UrlParameter.Optional }
);
AnArea is the name of the controller, not the area. If you want to navigate to some controller of this area you should always prefix your url with MyArea which is the name of the area.

Resources