11
votes

I've been searching for answers for this everywhere, but I can't seem to find any. I basically have an MVC application setup and I am using the built in AttributeRouting for my routes.

The folder structure looks like this;

  • Models
  • Views
  • Controllers
  • Areas
    • Member
      • MemberAreaRegistration.cs
      • Controllers
        • HomeController.cs
      • Views
        • Home
          • Account.cshtml

And then I wire up my routes in the global.asax like this;

public class Application : System.Web.HttpApplication {
   protected void Application_Start(){
      AreaRegistration.RegisterAllAreas();
      // other web optimization stuff
      RouteConfig.RegisterRoutes(RouteTable.Routes);
   }
}

So then, MemberAreaRegistration.cs is simple.

namespace App.Web.Areas.Member {
   public class MemberAreaRegistration: AreaRegistration {
      public override string AreaName { get { return "Member"; } }
   }
   public override void RegisterArea( AreaRegistrationContext context){ }
} 

And I try to wire it using the attributes...

/areas/member/controllers/homecontroller.cs

// ...
[Route("member/account")]
public ActionResult Account() { return View(); }
// ...

The problem is that this finds the route, but it cannot find the view. I get the following error;

The view 'Account' or its master was not found or no view engine supports the searched locations. The following locations were searched:

~/Views/Home/Account.aspx

~/Views/Home/Account.ascx

~/Views/Shared/Account.aspx

~/Views/Shared/Account.ascx

~/Views/Home/Account.cshtml

~/Views/Home/Account.vbhtml

~/Views/Shared/Account.cshtml

~/Views/Shared/Account.vbhtml

By all accounts, this should work fine - and if not, I expect the ~/area to at least be in the path it is trying to search. Do I have to wire something additional up to make this function?

I am using ASP.NET MVC 5.0

If I hardcode the absolute path of the view, it works. Obviously this is not a good situation though. I'd prefer it to find the view out of convention. But if I type return View("~/areas/member/views/home/account.cshtml"); I do get the view back - so I know it can access to file and that it is correct.

Here is my RouteConfig.cs per request

RouteConfig.cs

public class RouteConfig {
    public static void RegisterRoutes(RouteCollection routes) {
        // mvc attribute routing allows us to supersede normal routing mechanisms and
        // declare our routes a bit more verbosely
        routes.MapMvcAttributeRoutes();

        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapRoute(
            name: "default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
            namespaces: new[] { "App.Web.Controllers" }
        );
    }
}
1

1 Answers

23
votes

That's because, once you are defining your route as an action's attribute, ASP.NET MVC doesn't know which area it is in, hence it doesn't know where to look for Views.

In the Controller the Account action is in, try to explicitly specify a RouteArea attribute.

I'm writing this off the top of my head, but it should look like:

[RouteArea("Member")]
[RoutePrefix("member")]
public class HomeController: Controller {
    [Route("account")]
    public ActionResult Account() { return View(); }
}

or, alternatively:

[RouteArea("Member")]
public class HomeController: Controller {
    [Route("member/account")]
    public ActionResult Account() { return View(); }
}