Setting an alternate controller folder location in ASP.NET MVC

You can do this using Routing, and keeping the controllers in separate namespaces. MapRoute lets you specify which namespace corresponds to a route.

Example

Given this controllers

namespace CustomControllerFactory.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
           return new ContentResult("Controllers");
        }
    }
}

namespace CustomControllerFactory.ServiceControllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
           return new ContentResult("ServiceControllers");
        }
    }
}

And the following routing

 routes.MapRoute(
           "Services",
           "Services/{controller}/{action}/{id}",
            new { controller = "Home", action = "Index", id = UrlParameter.Optional },
            new string[] { "CustomControllerFactory.ServiceControllers" } // Namespace
        );


        routes.MapRoute(
            "Default", // Route name
            "{controller}/{action}/{id}", // URL with parameters
            new { controller = "Home", action = "Index", id = UrlParameter.Optional },
            new string[] { "CustomControllerFactory.Controllers"} // Namespace
        );

You should expect the following responses

/Services/Home

ServiceController

/Home

Controllers


In Asp.Net Core: I used AreaFeature library ServiceCollectionExtensions

First set your middleware;

    services.AddMvc(options => 
        options.EnableEndpointRouting = false).
        AddFeatureFolders().SetCompatibilityVersion(Microsoft.AspNetCore.Mvc.CompatibilityVersion.Latest);

In the extenssion:

return AddFeatureFolders(services, new FeatureFolderOptions());

implement as according your requirement:

 public static IMvcBuilder AddFeatureFolders(this IMvcBuilder services, FeatureFolderOptions options)
        {
            if (services == null)
                throw new ArgumentNullException(nameof(services));

            if (options == null)
                throw new ArgumentException(nameof(options));

            var expander = new FeatureViewLocationExpander(options);

            services.AddMvcOptions(o => o.Conventions.Add(new FeatureControllerModelConvention(options)))
                .AddRazorOptions(o =>
                {
                    o.ViewLocationFormats.Clear();
                    o.ViewLocationFormats.Add(options.FeatureNamePlaceholder + @"\{0}.cshtml");
                    o.ViewLocationFormats.Add(options.FeatureNamePlaceholder + @"\_Views\{0}.cshtml");
                    o.ViewLocationFormats.Add(options.FeatureFolderName + @"\Shared\{0}.cshtml");
                    o.ViewLocationFormats.Add(options.DefaultViewLocation);

                    o.ViewLocationExpanders.Add(expander);
                });

            return services;
        }

In my case i preferred a separated _View folder for views in the features folders like that

~/Features/Account/_Views/login.cshtml
~/Features/Account/AccountController.cs
~/Features/Account/AccountModel.cs