14

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.

user314827
  • 221
  • 1
  • 3
  • 8

8 Answers8

8

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.

user314827
  • 221
  • 1
  • 3
  • 8
  • 1
    I had a similar issue. In my case my link did not have the area name in the path and even though the correct controller was called, the view could not be found. That situation leaves me with the question of how the controller got called. – SOHO Developer Oct 05 '17 at 11:16
7

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...

Morgli
  • 71
  • 1
  • 1
  • 3
    This sort of worked for me but with another problem. The route is hitting the correct controller but the view is not found (It's looking in the main project directory for the default view instead of in the area, which is what I need). – JSideris Apr 09 '14 at 17:24
  • @jSideris i am having same issue. how did you solved this issue? – Jaimin Dave Jun 29 '17 at 09:21
5

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   
{
...
}
Jeff Widmer
  • 4,746
  • 6
  • 37
  • 51
4

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.

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
  • That is done by default in an ASP.NET MVC 2 web application in VS2008. It is part of the default setup of the global.asax – user314827 Apr 12 '10 at 20:57
  • Hi Robert, I re-checked all my controller namespaces. They all align with what they should be which is ProjectName.Areas.AreaName.Controllers. – user314827 Apr 12 '10 at 21:35
  • The error you are getting is exactly what I am faced with. The only difference being that I actually have the pertinent views present in the area specific view folder – user314827 Apr 12 '10 at 21:39
  • Perhaps you could new up a RouteValueDictionary in the controller like this: `System.Web.Routing.RouteValueDictionary routeData = RouteData.Tokens`, set a breakpoint, hover over the routeData variable, and see if you're getting an `area` key with the value `xyz`? That would verify that the route data is correct. – Robert Harvey Apr 12 '10 at 21:50
  • Note that the error you posted is not the same error I posted. The error I posted actually tries 8 different locations (4 for the area, and 4 for the root). – Robert Harvey Apr 12 '10 at 21:52
  • Basically what I have done is that I had a standard MVC project that I moved in to an area when I migrated to MVC 2.0 So now the root folders are empty barring the controllers that have one root controller that is used to dispatch default requests to the Area that my project now lies under. – user314827 Apr 12 '10 at 21:55
  • The global.asax has one route :- routes.MapRoute( "Default", // Default route "{controller}/{action}/{id}", new { controller = "Dispatch", action = "Index", id = UrlParameter.Optional } ); And the Area "xyz" has its default (even though this area has multiple controllers and views):- context.MapRoute( "Developers_default", "Developers/{controller}/{action}/{id}", new { action = "Index", id = UrlParameter.Optional } ); – user314827 Apr 12 '10 at 21:56
  • For some context, I do have a home controller in the root of my application for the initial (default) home Url. It performs a `RedirectRoute` into an area (specifying the name of the area route), and I stay in that area (or one of the other areas) for the remainder of the session. I only use root controllers for authentication. – Robert Harvey Apr 12 '10 at 21:59
  • I'm sorry what are you referring to ? I have controllers only in the area, other than the dispatch controller in the root. When I debug the project, the controllers in the area are the ones getting called. However for some reason when I try to return a View MVC tries to search for that view under the root views folders. – user314827 Apr 12 '10 at 22:01
  • Mind you, I don't use `UrlParameter.Optional` (not yet, anyway), and I think that might figure in here somehow. – Robert Harvey Apr 12 '10 at 22:03
  • Yes, this is exactly what I am doing. The dispatch controller is like your root home controller. It performs a redirect to action to a specific controller and an action in the area. – user314827 Apr 12 '10 at 22:03
  • 1
    I could do a redirecttoroute instead of a redirecttoaction. – user314827 Apr 12 '10 at 22:03
  • What I am saying is that I think it will work if you use `RedirectToRoute` instead of `RedirectToAction` in your dispatch controller. – Robert Harvey Apr 12 '10 at 22:05
  • Nope, that didn't work. I had a redirect to action in my DispatchController "Index" action which I now turned in to return RedirectToRoute("xyz_default",new{controller="Home", action = "Index"}); I get the same error. – user314827 Apr 12 '10 at 22:11
  • Your master page. Should it be in the root views/shared folder or in the area specific views/shared folder ? – user314827 Apr 12 '10 at 22:13
  • My master page is in the root. Currently I am using it for all views. – Robert Harvey Apr 12 '10 at 22:56
2

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 }
        );
    }
Raphael
  • 7,972
  • 14
  • 62
  • 83
2

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();
    }
}

}

tksdotnet1
  • 81
  • 6
1

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" }
);
kratenko
  • 7,354
  • 4
  • 36
  • 61
rav
  • 11
  • 1
1

I just had the same problem and solved it by setting the ascx's 'Build Action' property to 'Embedded Resource'.

John MacIntyre
  • 12,910
  • 13
  • 67
  • 106