Configuring Startup in .NET Core 3: Endpoint Routing and IHostApplicationLifetime

30th November 2019

.NET Core 3 was officially launched two months ago. The inclusion of Windows Forms and Windows Presentation Foundation (WPF) was one of the major changes. But, it also included a number of small changes, particularly when configuring the application.

How a .NET Core App Starts

Config Startup .NET Core 3 Endpoint Routing and IHostApplicationLifetime

One of the major changes between .NET Framework and Core apps is that .NET Core apps are based off a console application. You can build application models on top of the console application, such as a ASP.NET Core Application.

Before we run through the changes in .NET Core 3, it's worth noting what methods we need to call before our application begins.

We are going to take an example of an ASP.NET Core application. Below is how we launch a ASP.NET Core application:

// Program.cs
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;

namespace DotNetCore3
{
    public class Program
    {
        public static void Main(string[] args)
        {
            Host.CreateDefaultBuilder()
           .ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup<Startup>())
           .Build().Run();
        }
    }
}

Like in a console application, Program is the default class that is used if a Startup Object has not been set. The Main method inside the Program class will be used to launch the application.

Inside the Main method, we are calling a number of methods to launch our ASP.NET Core application. The ConfigureWebHostDefaults method is quite significant as this allows us to configure our application.

One thing that we can configure is the Startup class. The Startup class allows us to configure our application, such as what services we are including, to the connection string of our database.

We then have to build our configuration and then run it. With the Run method, it will lock the main thread of the console application until the application is shut down. Consequently, if the main thread wasn't locked down, the console application would finish immediately, and our web application wouldn't run.

Configuring the Startup Class

In the above example, you may have spotted this line:

.ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup<Startup>())

This is instructing the application to use the Startup class as it's configuration.

The Startup class has two methods associated with it.

  • ConfigureServices
  • Configure

Remove these methods will still allow you to compile your application. But, removing the Configure method will throw a runtime error. And, a method inside Configure is likely to rely on the ConfigureServices method, so actually, removing both of these methods is problematic.

From IApplicationLifetime to IHostApplicationLifetime

The Configure method allows you to dictate what Middleware is being used in your application. An example of this is MVC.

This is where there is a change for .NET Core 3 applications compared to 2.2. In the Configure method, you can pass in a IHostApplicationLifetime parameter. The IHostApplicationLifetime allows you to register certain tasks to run when your application triggers a lifetime event. These lifetime events are:

  • ApplicationStarted
  • ApplicationStopping
  • ApplicationStopped

If you want more detail about lifetime events, I've written an article that combines SignalR and RabbitMQ with one of these lifetime events.

The IHostApplicationLifetime has replaced IApplicationLifetime in .NET Core 3. IApplicationLifetime has now been deprecated and will be removed in future versions of .NET Core.

EnableEndPointRouting Set to True

The ConfigureServices method allows you to add services, such as Entity Framework or writing your own services to use in Dependency Injection.

It's at this point to tell you about another change in .NET Core 3 in the form of EndPoint Routing.

Now Endpoint Routing was around in .NET Core 2.2, but wasn't the default. With .NET Core 3, it is! What Endpoint Routing allows us to do is to combine the routing from the many different types of middleware (like MVC or SignalR) and combine them into one place.

EndPoint Routing is already configured in MVC under the EnableEndPointRouting property by default. But, if you want to explicitly enable it, you can do so by calling the following inside the ConfigureServices method:

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

By setting EnableEndPointRouting property to true, this means that when configuring your routes in the Configure method, you need to use the UseEndPoints method. As a result, the UseEndPoints method is not only used to configure MVC routes, but also routes in other libraries, such as SignalR.

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

You can turn off EndPoint Routing in a .NET Core 3 application and still use the UseMvc method inside the Configure method to configure your routes. But, it may not be in use for much longer...

An Example of the Startup Class

Below is an example of how the Startup class will look in a .NET Core 3 application.

// Startup.cs
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace DotNetCore3
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc(options =>
            {
                options.EnableEndpointRouting = true;
            });            
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IHostApplicationLifetime lifetime)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/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.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
            });
        }


    }
}

A Final Note...

This article in intended for .NET Core 3. Updated versions are rolled out on a regular basis. For instance, .NET Core 3.1 was launched on 14th November 2019. Changes may occur every time a new version is rolled out, so something to bare in mind.

About the author

David Grace

David Grace

Senior .NET web developer | ASP.NET Core | C# | Software developer

Free .NET videos

  • Do you want to watch free videos featuring .NET 7 new features?
  • How about what's new in C# 11?
  • Or a recap on the SOLID principles?
Watch our .NET videos