The ASP.NET Core templates have been updated to use the latest C# language features, and a new minimal hosting API in .NET 6. The main driver behind these changes is simplicity. The ASP.NET team want to remove unnecessary code from your app, so you have less code to understand and look after, and there is a lower barrier to entry for newer C# developers. They want to provide "a more focused, low ceremony way of creating a web application".
In a .NET 6 app, your services and middleware configuration take place in the Program.cs file instead
of being delegated to a separate Startup class with its constructor, ConfigureServices
and Configure
methods. Here's what the revised version of
Program.cs looks like:
var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddRazorPages(); var app = builder.Build(); // Configure the HTTP request pipeline. if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); app.MapRazorPages(); app.Run();
The first thing to notice is that the Main
method is missing. This is still, after all, a console app at heart. As of C# 9, introduced last year, the
Main
method is no longer necessary. Instead, this file utilises a feature called
top level statements, where the namespace, class declaration and Main
methods are generated by the compiler. You just start writing executable code, which the compiler places within the generated Main
method.
In .NET 5, the Program
class includes a large number of using
directives,
whether they were needed or not. This version doesn't have a single one. C# 10
introduces a new feature called global usings, where a
pre-defined selection of
using
directives are registered globally and are no longer required
in individual class files. The selection includes all the namespaces that you
tend to see at the top of every class file in an ASP.NET Core web app, so this
new feature greatly reduces the boilerplate noise in your code base.
Looking at the code itself, it does exactly the same thing as the Startup
class in .NET 5 and earlier. The code registers services and builds a pipeline.
But this is a lot simpler. It makes use of the new minimal hosting API, based
around the new WebApplicationBuilder
type through which you configure your
app. The WebApplicationBuilder
type has a number of properties that help to
simplify service registration and configuration:
Environment
- provides access to theIWebHostEnvironment
Services
- theIServiceCollection
that is injected intoConfigureServices
in previous versionsConfiguration
- representing among other things, theIConfiguration
injected into the olderStartup
class constructorLogging
- enabling logging configuration via theILoggingBuilder
Host
- anIHostBuilder
that enables configuration of host specific services including third party DI containersWebHost
- theIWebHostBuilder
represented bywebBuilder
parameter in theConfigureWebHostDefaults
method in the .NET 3.1/5 version of Program.cs
Services are added to the Services
property. The project template shows how
Razor Pages is configured:
var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddRazorPages();
You use the Configuration
property to access the IConfiguration
for
the app,
so that you can access connection strings and so on:
builder.Services.AddDbContext<MyContext>(options => { options.UseSqlServer(builder.Configuration.GetConnectionString("MyContext")); });
The Build
method on the WebApplicationBuilder
type
returns a configured application as a WebApplication
type, which is
new. The
WebApplication
represents a merger of the IApplicationBuilder,
IEndpointRouteBuilder
and IHost
interfaces which we are familiar with from current versions of ASP.NET Core. You can use your existing extension
methods on IApplicationBuilder
to build your pipeline -
UseStaticFiles
, UseRouting
and so on. And because it
implements IEndpointRouteBuilder
, no more lambdas required to call
MapRazorPages
(or MapControllers
etc). You can call that directly on the
WebApplication
instead.
So the big question is: do you need to update your startup code if you migrate your .NET 5 Razor Pages app to take advantage of the long term support provided by .NET 6? The answer is No. The two-file, generic host approach to app configuration is still supported. However, if you are in the middle of writing a book about Razor Pages which is scheduled to be published after .NET 6 is released, you might just have to redo all the code samples and update the nine chapters written so far to reflect the new way of doing things...
Speaking of which, my new book Razor Pages in Action is available to purchase in MEAP now, which gives you access to chapters as they are written (and amended). You can get 35% off the price of the book (along with all other Manning products) by quoting discount code au35bri when you make your purchase. You get the full version of the book when it is finally published in the first half of next year.
Final note - there are two new settings in the csproj file that determine how
new C# features are applied to your app - ImplicitUsings
and
Nullable
. The first determines whether implicit, or global usings
are enabled for the project (default is enabled
). The second,
Nullable
, enables you to opt in to
Nullable Reference Types which was introduced in C# 8 to help you avoid the dreaded
NullReferenceException
at runtime. The default is also
enabled
. The main consequence of this is that your project could end up with a
lot of new warnings:
Summary
Web app configuration in .NET 6 has been simplified to a single file to
reduce the concept count for developers approaching .NET for the first time. Two
new types are introduced - the WebApplicationBuilder
and the
WebApplication
. You don't need to use this pattern. The existing way of
doing things that make use of a Startup class is still supported. The new
project templates also embrace a number of newer C# features.