The Startup Class

ASP.NET Core applications are designed to be modular, in that the developer only includes features and services that they need. Every .NET Core application requires a startup class where the application's features and services are configured. By default, the name of this class is Startup, but it can be named anything.

The startup class is found in the Startup.cs file that's generated as part of the default template. It has a Configure method which is required and a ConfigureServices method, which is optional. The Configure method is used for configuring the request pipeline and the ConfigureServices method is used to make services available to the application.

The Request Pipeline

When requests are made to a web application, they need to be processed in some way. A number of considerations need to be taken into account. Where should the request be directed or routed to? Should it log details of the request? Should the application simply return the content of a file? Should it compress the response? What should happen if an exception is encountered while the request is being processed? Is the person making the request actually allowed to access the resource they have requested? How should cookies or other request-related data be handled?

Each of these processing actions are performed by separate components. The term used to describe these components is Middleware. Together, they form the request pipeline.

The Configure Method

Here is the template version of the Configure method in Razor Pages 3.x:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage(
    }
    else
    {
        app.UseExceptionHandler("/Error");
        // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

The parameters passed to the method are IApplicationBuilder and IWebHostEnvironment (IHostingEnvironment in pre-ASP.NET Core 3.0). No parameters are actually required, but the IApplicationBuilder is the component that configures the request pipeline by adding middleware to it. IWebHostEnvironment provides information about the environment that the application is currently running in.

This version of the Configure method examines the current environment (set via an environment variable called ASPNETCORE_ENVIRONMENT) to see if it is Development. If it is, middleware is added to the request pipeline that enables detailed error messages to be rendered to the browser if the application raises exceptions when it is running. The middleware is added using an extension method (in this case UseDeveloperExceptionPage()) on IApplicationBuilder, which is the recommended way to construct the request pipeline. If the environment is not Development (e.g is it Production), a middleware component is added that logs details about failed requests and redirects to a page named Error. This is the recommended behaviour for a live site, where the Error page displays a more user-friendly message rather than a stack trace.

Middleware is then added that enables the serving of static files (images, scripts, style sheets, PDF files etc), to configure routing within the application, authorisation and endpoint routing.

The ConfigureServices Method

ASP.NET Core makes extensive use of dependency injection (DI) - a technique that facilitates loose coupling of code. Components, or "services" are represented as abstractions, typically interfaces, as you have already seen in the Configure method with IApplicationBuilder. In DI, each abstraction is paired with an implementation (or "concrete") type. This pairing is stored in a dictionary-like structure so that when an abstraction is passed as a parameter to a method (particularly a constructor), the implementation type is instantiated and passed in by the DI container. The primary purpose of the ConfigureServices method is as a place to register implementation types for services that are needed by the application. It is also used to configure any options related to those services.

If it has been added to the Startup class, the ConfigureServices method is called before the Configure method. That makes sense, because the Configure method may attempt to reference services which need to be registered beforehand so that they can be resolved. This is the case with the default template where Razor Pages is registered:

public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages();
}

The AddRazorPages method is a wrapper for adding a substantial number of components to the service collection, including routing, model binding, caching, view engines and other components that Razor Pages requires. It also provides a place where options relating to the services can be configured. For example, The AddRazorPages method returns an IMvcBuilder, which offers a wide range of configuration options:

Configure Razor Pages options

The AddRazorPages method is new in ASP.NET Core 3.0. Prior to version 3.0, Razor Pages were enabled by calling the AddMvc method.

If you want to configure the root folder for Razor Pages to be something other than the default Pages, this is where you would do that:

public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages().AddRazorPagesOptions(options =>
    {
        options.RootDirectory = "/Content";
    });
}

Compatibility Version

A new setting, Compatibility Version was introduced in ASP.NET Core 2.1. This allows you to opt into or out of new features released as part of future versions which might break existing behaviour. For example, Areas was introduced in 2.1. This may have an adverse effect on the routing in some Razor Pages applications built using the default configuration found in version 2.0, which are subsequently upgraded to version 2.1 or later. The team behind ASP.NET Core decided that areas (and other features) should be enabled by default going forward.

The SetCompatibilityVersion method enables you to determine the version of the framework that your application should be compatible with, in respect of these default behaviours. It takes an enumeration specifying the framework version. All new applications built using the standard template that target version 2.1 have the compatibility version set to CompatibilityVersion.Version_2_1.

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

Even with this setting, you can selectively disable default behaviours:

// disable areas, but keep the other new default behaviours
services.AddRazorPages().AddRazorPagesOptions(options => {
    options.AllowAreas = false;
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

Alternatively, you can keep the version 2.0 defaults - either by specifying CompatibilityVersion.Version_2_0 or omitting the method - and then selectively enable new features:

// don't introduce the new behaviours, but allow me to use areas
services.AddRazorPages().AddRazorPagesOptions(options => {
    options.AllowAreas = true;
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_0);
Last updated: 10/01/2020 07:34:14

© 2018 - 2024 - Mike Brind.
All rights reserved.
Contact me at Outlook.com