Areas partition a large ASP.NET Core application into distinct sections, each with its own controllers, views, and optionally models. A common use case: an application with a public-facing blog (/blog/*), an admin panel (/admin/*), and an API (/api/*). Without areas, all controllers and views are in a flat structure and naming conflicts become a problem as the application grows. Areas give each section its own namespace, folder structure, and route prefix, keeping sections cleanly separated.
Creating and Configuring an Area
// ── Project structure with an Admin area ─────────────────────────────────
// BlogApp.Web/
// ├── Areas/
// │ └── Admin/
// │ ├── Controllers/
// │ │ ├── DashboardController.cs
// │ │ └── PostsController.cs ← different from root PostsController!
// │ └── Views/
// │ ├── Dashboard/
// │ │ └── Index.cshtml
// │ ├── Posts/
// │ │ ├── Index.cshtml
// │ │ └── Create.cshtml
// │ └── Shared/
// │ └── _AdminLayout.cshtml
// ├── Controllers/
// │ └── PostsController.cs ← root PostsController (different class)
// └── Views/
// └── Posts/
// └── Index.cshtml
// ── Area controller — must have [Area] attribute ──────────────────────────
namespace BlogApp.Web.Areas.Admin.Controllers
{
[Area("Admin")]
[Authorize(Roles = "Admin")]
[Route("admin/[controller]/[action]")]
public class PostsController : Controller
{
// GET /admin/posts/index
public async Task<IActionResult> Index() => View();
// GET /admin/posts/create
[HttpGet]
public IActionResult Create() => View(new CreatePostViewModel());
[HttpPost, ValidateAntiForgeryToken]
public async Task<IActionResult> Create(CreatePostViewModel model)
{
if (!ModelState.IsValid) return View(model);
await _service.CreateAsync(model.ToRequest(), User.GetUserId());
TempData["Success"] = "Post created.";
return RedirectToAction(nameof(Index));
}
}
}
// ── Register area routing in Program.cs ───────────────────────────────────
app.MapAreaControllerRoute(
name: "admin",
areaName: "Admin",
pattern: "admin/{controller=Dashboard}/{action=Index}/{id?}");
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
[Area("Admin")] attribute on the controller is mandatory — without it, the controller is not associated with any area even if it is in the Areas/Admin/Controllers/ folder. The folder location is conventional and helps organisation, but the routing system uses the [Area] attribute for the actual area association. Missing the [Area] attribute is the most common area configuration mistake.<a asp-area="Admin" asp-controller="Posts" asp-action="Index">Admin Posts</a>. Without asp-area, the Tag Helper generates a link to the root PostsController, not the Admin area one. Ambient route values include the current area — so from within the Admin area, links to Admin controllers do not need asp-area, but links from the root to the Admin area always do.Areas/{AreaName}/Views/{Controller}/{Action}.cshtml, then Areas/{AreaName}/Views/Shared/{Action}.cshtml, then the root Views/Shared/{Action}.cshtml. This means area views can fall back to root shared views (like Error.cshtml), which is usually correct. However, if you have a root shared layout and an area layout with the same name, the area layout shadows the root layout only within the area — as expected. Test view resolution after adding a new area to verify views are found correctly.Area Link Generation
// ── In a root controller — link to area ───────────────────────────────────
string adminUrl = Url.Action("Index", "Dashboard", new { area = "Admin" });
// → /admin/dashboard/index
// ── In a view — Tag Helper with asp-area ──────────────────────────────────
<a asp-area="Admin" asp-controller="Posts" asp-action="Create">
Admin: New Post
</a>
@* → /admin/posts/create *@
<a asp-area="" asp-controller="Posts" asp-action="Index">
Public Blog
</a>
@* asp-area="" explicitly escapes any ambient area to link to root controller *@
Common Mistakes
Mistake 1 — Missing [Area] attribute on the controller (area routing ignored)
❌ Wrong — controller in Areas/Admin/ but missing [Area(“Admin”)]; treated as a root controller.
✅ Correct — always add [Area(“Admin”)] to every controller inside the Admin area folder.
Mistake 2 — Not specifying asp-area when linking to area controllers
❌ Wrong — link goes to root PostsController instead of Admin area PostsController:
<a asp-controller="Posts" asp-action="Index">Admin</a> @* missing asp-area="Admin" *@
✅ Correct — always include asp-area="Admin" when generating links to area controllers from outside the area.