Problem
How to structure a large ASP.NET Core MVC application into logical groupings.
Solution
In an empty project, update Startup
class to add services and middleware for MVC:
public void ConfigureServices(
IServiceCollection services)
{
services.AddMvc();
}
public void Configure(
IApplicationBuilder app,
IHostingEnvironment env)
{
app.UseDeveloperExceptionPage();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "area",
template: "{area:exists}/{controller=Home}/{action=Index}/{id?}");
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
Create a folder structure like:
Add files to Controllers and Views folders (Area1 shows below):
Add [Area]
attribute to controllers in Area1 and Area2 folder:
[Area("Area1")]
public class HomeController : Controller
[Area("Area2")]
public class HomeController : Controller
Discussion
MVC separate application concerns using Models, Views and Controllers. For larger applications, Areas provide a way to group these three concerns into another high level grouping. For instance, you may want to split your application into modules, each one containing its own MVC structure.
For routing purposes, there is another route parameter area
available (in addition to controller
and action
). You could think of areas as namespaces, under which controllers live. The area
route parameter is also available as ambient value if it’s in context of current request, see Routing. Below, you can see how area
parameter for Area1 links is left out, since this page is in Area1 (see also Link Generation section below):
<p><strong>You are here: </strong>Area1/Home/Index</p>
<a asp-area="" asp-controller="Home"
asp-action="Index">Home/Index</a>
<a asp-area="" asp-controller="Home"
asp-action="About">Home/About</a>
<a asp-controller="Home"
asp-action="Index">Area1/Home/Index</a>
<a asp-controller="Home"
asp-action="About">Area1/Home/About</a>
<a asp-area="Area2" asp-controller="Home"
asp-action="Index">Area2/Home/Index</a>
<a asp-area="Area2" asp-controller="Home"
asp-action="About">Area2/Home/About</a>
In order to use Areas in your project, you first setup a folder structure with Areas root folder and sub-folders for each area (along with its controller, models and views). Note that the folder structure is important for views because MVC will search for the views in the following sequence:
Once the folder structure is in place, you can decorate controllers with [Area]
attribute:
[Area("Area1")]
public class HomeController : Controller
Link Generation
Below is a table of route parameters required when generating a link from one location to a different location, location being {area}/{controller}/{action}
:
Missing route parameters mean that MVC will pick those values up from the request context. I personally find it easier to specify all the route parameters to make maintenance easier. The sample for this post has links on various pages to show how ambient values work:
Layout Pages
Razor pages inside Areas folder can use the Layout page located outside it (e.g. in /Views/Shared folder). You can define a separate Layout page for each Area too. Yet another approach is to define a common Layout page outside Areas folder and Layout pages inside Areas folder use them as their layout, creating a nested Layout page structure. Below is a Layout page for Area2 that uses shared layout page (note you need an absolute path to shared layout):
@{
Layout = "/Views/Shared/_Layout.cshtml";
}
<div>
<nav style="background-color: lightgray">
<h2>Area2 Layout</h2>
</nav>
@RenderBody()
</div>