Change the Default Asp.Net Core Layout to Use Feature Folders

August 30, 2020

One of the irritating things about the Asp.Net Core default project is that the various parts of your system are arranged by type, as opposed to function. For example, if you’re working on the Accounts page, you’re likely going to want to change the view, the controller and, perhaps, the model; you are, however, unlikely to want to change the Sales Order controller as a result of your change: so why have the AccountsController and SalesOrderController in the same place, but away from the AccountsView?

If you create a new Asp.Net Core MVC Web App:

Then you’ll get a layout like this (in fact, exactly like this):

If your web app has two or three controllers, and maybe five or six views, then this works fine. When you start getting a larger, more complex app, you’ll find that you’re scrolling through your solution trying to find the SalesOrderController, or the AccountsView.

One way to alleviate this, is to re-organise your project to reference features in vertical slices. For example:

There’s not much to either of these, but let’s just put them in for the sake of completeness; the View:

[code lang=“html”] @{ ViewData[“Title”] = “Wibble Page”; }


And the controller:

[code language="csharp"]
namespace WebApplication1.Wibble
    public class WibbleController : Controller
        public IActionResult Index()
            return View();

The problem here is that the engine won’t know where to look for the views. We can change that by changing the ConfigureServices method in Startup.cs:

[code language=“csharp”] public void ConfigureServices(IServiceCollection services) { … services.Configure(options => { options.ViewLocationFormats.Clear(); options.ViewLocationFormats.Add($“/Wibble/{{0}}{RazorViewEngine.ViewExtension}”); options.ViewLocationFormats.Add($“/Views/Shared/{{0}}{RazorViewEngine.ViewExtension}”); }); }

Let's also change the default controller action (in the **Configure** method of **Startup.cs**):

[code language="csharp"]
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
            if (env.IsDevelopment())
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see

            . . . 
            app.UseEndpoints(endpoints =>
                    name: "default",
                    pattern: "{controller=Wibble}/{action=Index}/{id?}");

There’s more than a few libraries that will handle this for you (here’s one by the late Scott Allen), but it’s always nice to be able to do such things manually before you resort to a third-party library.

Profile picture

A blog about one man's journey through code… and some pictures of the Peak District

© Paul Michaels 2022