Areas In Razor Pages

Support for Areas was added to Razor Pages with the release of ASP.NET Core 2.1. They have long been used in MVC applications as a way to separate logical chunks of large applications into semi-independent modules to facilitate team working etc. Here, I explore how to use areas in a Razor Pages application.

The first thing to mention is that areas in Razor Pages differ to the ones that you find in an MVC application. An MVC area is like a mini MVC application, including all of the folders that you associate with MVC - Model, Views and Controllers. MVC areas have tooling support within Visual Studio, enabling the quick scaffolding of all the required artefacts:

Areas in MVC

This kind of support is not available (at the time of writing, at least) to Razor Pages areas. To add areas to Razor Pages, you simply add a new folder to the application and name it Areas. The folder must be at the root of the application:

Areas in Razor Pages

The name of the Areas folder is non-negotiable. You cannot configure it to be something other than "Areas". 

Once you have done this, you add additional subfolders for each item that represents a distinct area of the application, in this example, Customers, Orders and Products. These form the names of the areas:

Areas in Razor Pages

Razor Pages in areas must have their own root folder just as in the main application. Therefore you will need to add a Pages folder to each area:

Areas in Razor Pages

Again, the name of the root folder for the pages is not configurable.

Having done that, you can begin to add Razor Pages to each area. One thing to mention is that the PageModel class will be generated with a namespace matching the file path to the file e.g. WebApplication1.Areas.Customers.Pages.IndexModel. The @model directive in the content page will not pick this up by default, so you can either fully qualify the @model directive every time you add a new page to the area, or you can add a _ViewImports.cshtml_ file to the Pages folder in the area, specifying the namespace for all pages in the folder:

For demo purposes, the current Index.cshtml file in the Customers area is very brief:

You should be able to navigate to it by firing up the application and appending /customers to the URL, but the output is very bland and has no styling:

Areas in Razor Pages

You can make use of the default layout file by copying the _ViewStart.cshtml file from the root Pages folder to the Areas folder:

Areas in Razor Pages

Now the pages in all areas will automatically make use of the default layout page:

Areas in Razor Pages

Alternatively, you can specify a different layout file altogether, and only affect one area. The following example makes use of a Layout page located in the Pages folder of the Customers area:

@{
    Layout = "/Areas/Customers/Pages/_Layout.cshtml";
}

This ViewStart file can be placed in the Customers folder or the Customers/Pages folder to affect all pages in the Customers area only. Pages in other areas will still be governed by the ViewStart file placed in the Areas folder.

Links and Redirects To Areas

When you use the anchor taghelper to generate your links to items in areas, you must use the asp-area attribute:

...unless you are generating links between pages within the same area. Here is the Customers area Index page again with a link to Create.cshtml, also located in the Customers area:

If using the RedirectToPage method to transfer someone to a location within an area, you should use the overload that takes an object representing route values to specify the area:

The leading slash is not necessary when using RedirectToPage from within a Razor page, but you must use it when redirecting from outside of a Razor page, such as from an MVC controller.

Routing

Route templates for items in areas are generated by prepending the area name to the file path of the page rooted in the area's Pages folder. For example, the template generated for the item with a relative path of /Areas/Customers/Pages/Create.cshtml will be "Customers/Create". This will clash with an item located at /Pages/Customers/Create/Index.cshtml or /Pages/Customers/Create.cshtml, unless constraints are explicity added to the route templates to disambiguate them.

Configuration and customisation

Customisation of conventions around areas in Razor Pages is limited. As I mentioned earlier, the location of areas is restricted to a folder named Areas. Razor page files must be placed in a folder named Pages within each area. Areas are enabled through one of two mechanisms. The first is by default if you to set the compatibility version to 2.1 in the Startup ConfigureServices method:

services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

The second method is to set the RazorPagesOptions.AllowAreas property to true (also in ConfigureServices):

services.AddMvc().AddRazorPagesOptions(options =>
{
    options.AllowAreas = true;
});

Note that your application still needs to be targeting .NET Core 2.1 for this to work. It is how you elect to opt in to specific 2.1 behaviours if you choose not to set the compatibility version.

Summary

Areas were added to Razor Pages primarily to assist with the introduction of Razor class libraries, specifically the introduction of Identity as a class library. As such, they offer a way of dividing a complex Razor Pages application up by feature, but in reality, the same can be achieved with a little less ceremony by adding feature folders to the Pages folder e.g. /Pages/Customers/, /Pages/Orders/ etc. Nevertheless, if you are used to working with areas in MVC, it's good to know that they are available in Razor Pages too.