I'm using MVC 3 and MVC Contrib to have portable areas. The problem is, the portable areas have similar views (e.g. Home, User Management...).
For example, each portable area has a Home view (Views/Home/Index.cshtml) and a Home Controller (Controllers/Home.cs). The routing is set up so that to access the page, I would go to MySite/PortableAreaName/Controller/View.
The problem is that it only load the first Portable Area's Home and User Management pages. It finds that view first, then loads it regardless of the area specified in the URL.
I could just prefix everything (e.g. Area1Home, Area1UserManagement), but I'd rather find a more scalable solution. If we get 50+ portable areas each with 10 views, we'd either have to track which view names we used or prefix every single view.
Any suggestions? If you need more info, let me know.
Update 1 - Did Not Work
Resolved using the article provided by twang and adding the following code to the Main Project ("PortableAreas" in the linked article).
Article: http://elegantcode.com/2012/04/06/mvc-portable-areas/
Main Project > Global.asax.cs
protected void Application_Start()
{
// ...
AreaRegistration.RegisterAllAreas();
PortableAreaRegistration.RegisterEmbeddedViewEngine();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
// ...
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Login", action = "Index", id = UrlParameter.Optional },
new string[] { "PortableAreas.Controllers" } // main project namespace
);
}
Portable Area > MyPortableAreaRegistration.cs
public class MyPortableAreaRegistration : PortableAreaRegistration
{
public override string AreaName
{
get
{
return "MyPortableArea";
}
}
public override void RegisterArea(AreaRegistrationContext context, IApplicationBus bus)
{
RegisterRoutes(context);
RegisterAreaEmbeddedResources();
}
private void RegisterRoutes(AreaRegistrationContext context)
{
context.MapRoute(
AreaName + "_default",
base.AreaRoutePrefix + "/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional },
new[] { "MyPortableArea.Controllers", "MvcContrib" }
);
}
}
As far as I understand, the following locations are the default for resources:
- MyPortableArea/Content/Images
- MyPortableArea/Scripts
As long as you keep your resources in those folders, you shouldn't to register them.
Update 2
The previous fix did not work. Even with the code above it still sometimes loads the wrong views, resources, etc. Anyone know how to fix this?
When I debug, it goes to the right controller and the right view within that controller, but loads the wrong view (e.g. makes it to Area2's controller and Area2's Home page method, but loads Area1's home page.
E.g. I have 2 portable areas, but it always loads the first one
MyPortableArea1/Controls/Home, MyPortableArea1/Scripts/Views/Home/index.js MyPortableArea2/Controls/Home, MyPortableArea2/Scripts/Views/Home/index.js
I think it's because it registers all of them at once? Then when it finds a match for the route, it uses the first match (which sometimes is wrong).
Update 3
After stepping through the code, it seems the sections in my layout are what is not loading correctly. For example, it reaches MyPortableArea2's HomeController > Index(), loads the layout, then the layout loads MyPortableArea1's content in the @RenderBody() section.
Update 4
Updated to the latest version of MvcContrib from http://mvccontrib.codeplex.com/. This did not work.
Update 5
So I did a little test and figured out why it loads the wrong page: it can't find the Area at all. It's like it's not even in the system!
E.g. PortableArea1/Home/Index
public ActionResult Index()
{
return View("~/Areas/PortableArea1/Views/Home/Index.cshtml");
}
E.g. PortableArea2/Home/Index
public ActionResult Index()
{
return View("~/Areas/PortableArea2/Views/Home/Index.cshtml");
}
When it's loading the wrong page, I now get an error saying the View was not found. Why isn't it loading my Portable Area??
You may want to override RegisterAreas(), and implement RegisterRoutes() for each area.
Here is a good article explains well: http://elegantcode.com/2012/04/06/mvc-portable-areas/
Hope it helps.