Adding a Logger With the .NET 6 Minimal Hosting Model
With the release of .NET 6, Microsoft introduced a new hosting model for ASP.NET Core. In short, it takes the old .NET Core model, puts it all into one file, and reduces the amount of code considerably.
Now, it’s not required to use the new hosting model. I have already transferred older .NET 5 applications to .NET 6 without it (the transition only required changing the target framework). But the simplicity of the new model, and the fact that it’s considered the default by Microsoft, warrants attention. I could see teams wanting to switch to the new hosting model, as I wanted to do the same thing for some demo applications I use to test Loupe.
So I figured this would be an excellent opportunity to go over adding a logger to the new host. This article will cover a basic log-to-file setup with Serilog and logging directly to Loupe. Hopefully, that will help you test the new hosting model and see if it’s a good choice for your applications.
Let’s Start With What’s Already Included
If I just open up a template ASP.NET Core application on .NET 6, it uses the new hosting model, and Microsoft.Extensions.Logging (MEL) is still available as the default. MEL is the standard logging API across .NET Core. It captures exceptions and lets you log directly to it on .NET 6, the same way you have before.
So, to use a capable logger on .NET 6, you don’t need to add anything! It’s included. But MEL is limited in available log providers out-of-the-box, so it’s worth looking at the other providers available anyways. Let’s start with a popular choice across .NET for logging to file and a personal favorite of mine: Serilog.
Quickly Log to a File With the New Hosting Model
There are many ways to log to a file on .NET 6, but I would start with Serilog. It’s a structured logging framework with excellent formatting options and a simple setup.
The current documentation for Serilog shows you how to log to a file using the generic hosting model already. We can easily adapt those directions for the .NET 6 hosting model, as it largely works the same way. What we need to do is just include the
Build(). Additionally, I want to add Serilog.Extensions.Logging to use Serilog as a MEL provider, so I’ll clear providers and set that up.
This is what the Program.cs file looks like through to the
var builder = WebApplication.CreateBuilder(args); Log.Logger = new LoggerConfiguration() .MinimumLevel.Debug() .WriteTo.File("logs/myapp.txt", rollingInterval: RollingInterval.Day) .CreateLogger(); // Add services to the container. builder.Services.AddRazorPages(); builder.Logging.ClearProviders(); builder.Logging.AddSerilog(); //Build var app = builder.Build(); //...
Note there is no using statement in this sample. That’s because, for something as ubiquitous as a logger, it makes sense to use a global using statement instead. Global using statements were introduced in C#10, and several of them are generated automatically for the new .NET 6 projects. You can’t write your own statements into the auto-generated file, so I’d make a separate file instead (I made a file called GlobalUsings.cs). Of course, you can just stick with normal using statements and be just fine.
Otherwise, the code sample shows all you need to start. You can always get fancier by adding additional formatting, applying enrichers, or outputting to a dedicated log viewer. But starting with a simple example like the one above puts you in a good position to refine the implementation as needed.
Adding Loupe to the New Hosting Model
The current Loupe “getting started” documentation for .NET Core is written for the generic host, but easy to adapt for the new hosting model. Using the migration code samples provided by Microsoft, I wrote the following Loupe configuration:
var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddRazorPages(); builder.Services.AddHttpContextAccessor(); //Requierd Service for Loupe builder.Host.AddLoupe(builder => builder.AddAspNetCoreDiagnostics() .AddPerformanceCounters()) .AddLoupeLogging(); //Build var app = builder.Build(); //...
The above sample is a basic Loupe setup using the optional performance counters package, and adding Loupe as a MEL provider. No using statements for the same reasons as the Serilog sample: it makes sense to create global using statements for your logging. For reference, these are the statements I would include in a separate file:
//GlobalUsings.cs global using Loupe.Agent.Core.Services; global using Loupe.Agent.AspNetCore; global using Loupe.Agent.PerformanceCounters; global using Loupe.Extensions.Logging;
Note the added
Will These Loggers Work on .NET 7?
Not every team using .NET 6 will want to move to .NET 7 November of 2022, nor will every migration want to target .NET 7 either.
.NET 6 has a longer support period than .NET 7, and the latest updates in .NET 7 may not be impactful enough to make up for it. Still, .NET 7 has updates and performance improvements beneficial for some projects.
So I tested Serilog and Loupe on the .NET 7 preview. You can read more about this process here. The short version is that they both work. So if you want to use .NET 7 when it’s finally out, don’t worry that the logger will hold you back.
Less Code, Same Capabilities
The new hosting model was nice to use, and it didn’t take long to adapt configurations for it. If nothing else, it’s worth playing around with to see if it can work for you. I wouldn’t say it’s necessary for every project, but it’s always worth investigating ways to simplify your application.
If you want to play around with a new log viewer as well, give Loupe a shot. You can use our free desktop log viewer for detailed local log viewing. It’s a great way to get familiar with dedicated log viewing software. Our Loupe 5 software goes a step further though, and provides a centralized-logging system you can access on any desktop with a browser. You can learn more about our free trial here, or watch a demo of Loupe 5 below.