Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVC Routing picking up Area controllers at root

I'm having difficulties with my controllers that are in an Area answering requests on routes that aren't for the area. So I have a setup like this (Extra stuff cut):

/Areas/Security/Controllers/MembersController.cs
/Areas/Security/SecurityAreaRegistration.cs
/Controllers/HomeController.cs

I have my area for security defined:

namespace MyApp.Web.Areas.Security
{
    public class SecurityAreaRegistration : AreaRegistration
    {
        public override string AreaName
        {
            get
            {
                return "Security";
            }
        }

        public override void RegisterArea(AreaRegistrationContext context)
        {
            context.MapRoute(
                "Security_default",
                "Security/{controller}/{action}/{id}",
                new { action = "Index", id = UrlParameter.Optional }
            );
        }
    }
}

And my global routing rules:

        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
        routes.IgnoreRoute("{*robotstxt}", new { robotstxt = @"(.*/)?robots.txt(/.*)?" });
        routes.IgnoreRoute("{*favicon}", new { favicon = @"(.*/)?favicon.ico(/.*)?" });

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

In my global asax I'm doing quite a few things but the relevant part is that I call AreaRegistration.RegisterAllAreas(); then I call the routing function that does the above.

But my problem is that requests for "/Members/" are hitting my Members controller using my "Default" route... even though the controller's not in the namespace I specified. Then when it tries to run it can't find it's Views cause they're defined in the Area and it's trying to find them in the overall Views folders. I tried making the route namespace "Weird.Namespace.With.No.Content" and it STILL hits the Members controller - I can't find any way to make it not use that controller. How do I make it not answer requests that aren't in it's area?

like image 965
fyjham Avatar asked Jan 10 '23 18:01

fyjham


2 Answers

Ended up finding a solution by changing the Route to:

    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
        namespaces: new string[] { "MyApp.Web.Controllers" }
    ).DataTokens["UseNamespaceFallback"] = false;

For some reason with that unset it seemed to always find my Controllers no matter where they were and totally disregard my namespaces - even from other referenced assemblies. Looking through the ILSpy of DefaultControllerFactory it looks like GetControllerType eventually falls back to searching absolutely every controller if it doesn't find the controller in the namespaces you asked for...

This flag seems to be set automatically on the Routes I made in a specific area, but not on the ones I made globally. When I set it on the global ones they began behaving how I had originally expected. I have no idea why you'd ever want to turn this on...

like image 177
fyjham Avatar answered Jan 18 '23 19:01

fyjham


You should register the namespace on your area as well.

public override void RegisterArea(AreaRegistrationContext context)
    {
        context.MapRoute(
            "Security_default",
            "Security/{controller}/{action}/{id}",
            new { action = "Index", id = UrlParameter.Optional },
            new []{ "MyApp.Web.Areas.Security.Controllers"},
        );
    }

And then make sure all your controllers are in their appropriate namespaces.

like image 31
Søren Lorentzen Avatar answered Jan 18 '23 19:01

Søren Lorentzen