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.
Related
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
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
I am in the process of debugging a routing issue on my MVC 3 application and I am using Phil Hacks routing debugger.
I cannot seem to work out where the route highlighted in yellow below is originating. Each time I run my application with the following request
http://www.mywebsite.com/auth/login?ReturnUrl=/
this route comes first and then gives me a 404 error as I do not have an index action. As you can see I have set my default routes to use the Login action method but still this route persists.
I have the following route configurations:
AuthAreaRegistration
public class AuthAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Auth";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"login",
"auth/login/{*returnPath}",
new { controller = "Auth", action = "LogIn", id = UrlParameter.Optional }
);
context.MapRoute(
"Auth_default",
"Auth/{controller}/{action}/{id}",
new { controller = "Auth", action = "LogIn", id = "" }
);
}
}
Global.asax (Using T4 MVC Templates)
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Home",
"{controller}/{action}/{id}",
MVC.Home.Index(), new { id = UrlParameter.Optional },
new string[] { "MyNamespace.WebUI.Controllers" }
);
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
MVC.Home.Index(), new { id = UrlParameter.Optional },
new string[] { "MyNamespace.WebUI.Controllers" }
);
}
I don’t like to answer my own question but after a day of trying to solve this problem I thought I would post the answer in case anyone else has the same issue.
It turns out that my application was holding onto old routes and populating them into my route collection. I deleted all the files in my bin folder and rebuilt my solution and everything worked as it should.
I have answered this question in a little more detail here:
Does ASP.NET MVC create default routes for areas
I think the problem is in the fact that you have an area called Auth and a controller called Auth outside of the areas.
MVC will try to match your url against Auth area first but you actually want it to hit your auth controller outside an area.
The best way to solve it imho is to avoid a ambiguous names of controllers/areas.
I have a project that is using MVC areas. The area has the entire project in it while the main "Views/Controllers/Models" folders outside the Areas are empty barring a dispatch controller I have setup that routes default incoming requests to the Home Controller in my area.
This controller has one method as follows:-
public ActionResult Index(string id)
{
return RedirectToAction("Index", "Home", new {area = "xyz"});
}
I also have a default route setup to use this controller as follows:-
routes.MapRoute(
"Default", // Default route
"{controller}/{action}/{id}",
new { controller = "Dispatch", action = "Index", id = UrlParameter.Optional }
);
Any default requests to my site are appropriately routed to the relevant area. The Area's "RegisterArea" method has a single route:-
context.MapRoute(
"xyz_default",
"xyz/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
My area has multiple controllers with a lot of views. Any call to a specific view in these controller methods like "return View("blah");
renders the correct view. However whenever I try and return a view along with a model object passed in as a parameter I get the
following error:-
Server Error in '/DeveloperPortal' Application.
The view 'blah' or its master was not found. The following locations were searched:
~/Views/Profile/blah.aspx
~/Views/Profile/blah.ascx
~/Views/Shared/blah.aspx
~/Views/Shared/blah.ascx
It looks like whenever a model object is passed in as a param. to the "View()" method [e.g. return View("blah",obj) ] it searches for the view
in the root of the project instead of in the area specific view folder.
What am I missing here ?
Thanks in advance.
Solved ! A couple of my "RedirectToAction" calls were not specifying the area name explicitly in the routeobject collection parameter of that method. Weird though, that that is required even though the controllers Redirecting are all in the same area. Also, the HtmlActionLinks work fine when I don't specify the new {area="blah"} in its routeobject collection, so I wonder why the controller action calls to RedirectToAction() need that even though both the calling and the called controller actions are all within the same area.
If you use instead of
context.MapRoute(
"xyz_default",
"xyz/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
use
context.MapRoute(
"xyz_default",
"{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
in your
xyzAreaRegistration.cs
then you don't need to explicitly specify your area in any link...
Add the RouteArea attribute on the Controller class so MVC knows to use the "XYZ" Area for the views (and then you can set the AreaPrefix to empty string so routes do not need to start with "XYZ").
[RouteArea("Xyz", AreaPrefix = "")]
public class XyzController : Controller
{
...
}
If this is a routing problem, you can fix it by registering your area routes first. This causes the routing engine to try matching one of the area routes, before matching a root route:
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
If I force an error by renaming one of my views folders in my areas application, I get a different error than yours:
The view 'Index' or its master was not found. The following locations
were searched:
~/Areas/xyz/Views/Document/Index.aspx
~/Areas/xyz/Views/Document/Index.ascx
~/Areas/xyz/Views/Shared/Index.aspx
~/Areas/xyz/Views/Shared/Index.ascx
...and then the usual root view folders..
..which is the pattern of subdirectories it would search if it thought it was in an area.
Check the generated code at MyAreaAreaRegistration.cs and make sure that the controller parameter is set to your default controller, otherwise the controller will be called bot for some reason ASP.NET MVC won't search for the views at the area folder
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"SomeArea_default",
"SomeArea/{controller}/{action}/{id}",
new { controller = "SomeController", action = "Index", id = UrlParameter.Optional }
);
}
For those who are looking for .net core solution please use
app.UseMvc(routes =>
{
routes.MapRoute(
name : "areas",
template : "{area:exists}/{controller=Home}/{action=Index}/{id?}"
);
});`
If you have some code in main project and some code in areas use the following code.
app.UseMvc(routes => {
routes.MapRoute(
name: "areas",
template: "{area:exists}/{controller=Home}/{action=Index}/{id?}");
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
Note make sure you have areas defined in your controller
[Area("Test")]
public class TestController : Controller
{
public IActionResult Index()
{
return View();
}
}
}
I just had the same problem and solved it by setting the ascx's 'Build Action' property to 'Embedded Resource'.
Try this code. Do changes in Area Registration File...
context.MapRoute(
"YourRouteName", // Route name //
"MyAreaName/MyController/{action}", // URL with parameters //
new {
controller = "MyControllerName",
action = "MyActionName", meetId = UrlParameter.Optional
}, // Parameter defaults
new[] { "Your Namespace name" }
);
I tried implementing Phil's Areas Demo in my project
http://haacked.com/archive/2008/11/04/areas-in-aspnetmvc.aspx.
I appended the Areas/Blog structure in my existing MVC project and I get the following error in my project.
The controller name Home is ambiguous between the following types:
WebMVC.Controllers.HomeController
WebMVC.Areas.Blogs.Controllers.HomeController
this is how my Global.asax looks.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapAreas("{controller}/{action}/{id}",
"WebMVC.Areas.Blogs",
new[] { "Blogs", "Forums" });
routes.MapRootArea("{controller}/{action}/{id}",
"WebMVC",
new { controller = "Home", action = "Index", id = "" });
//routes.MapRoute(
// "Default", // Route name
// "{controller}/{action}/{id}",// URL with parameters
// new { controller = "Home", action = "Index", id = "" }
// // Parameter defaults
//);
}
protected void Application_Start()
{
String assemblyName = Assembly.GetExecutingAssembly().CodeBase;
String path = new Uri(assemblyName).LocalPath;
Directory.SetCurrentDirectory(Path.GetDirectoryName(path));
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new AreaViewEngine());
RegisterRoutes(RouteTable.Routes);
// RouteDebug.RouteDebugger.RewriteRoutesForTesting(RouteTable.Routes);
}
If I remove the /Areas/Blogs from routes.MapAreas, it looks at the Index of the root.
In ASP.NET MVC 2.0, you can include the namespace(s) for your parent project controllers when registering routes in the parent area.
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = "" },
new string[] { "MyProjectName.Controllers" }
);
This restricts the route to searching for controllers only in the namespace you specified.
Instead of WebMVC.Areas.Blogs and WebMVC, use WebMVC.Areas.Blogs and WebMVC.Areas.OtherAreaName. Think of the area name as the namespace root, not an absolute namespace.
You can prioritize between multiple controllers with the same name in routing as follows
E.g., I have one controller named HomeController in Areas/Admin/HomeController
and another in root /controller/HomeController
so I prioritize my root one as follows:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", // Parameter defaults
id = UrlParameter.Optional },
new [] { "MyAppName.Controllers" } // Prioritized namespace which tells the current asp.net mvc pipeline to route for root controller not in areas.
);