Skip to content

Getting started with ASP.NET Core 6

David P edited this page Nov 15, 2025 · 45 revisions

ℹ️ See also example in GitHub


This tutorial is for ASP.NET Core 6.

0. Create a new ASP.NET Core project

In Visual Studio 2022. Version 17.0+ is needed

1. Add dependency in csproj manually or using NuGet

Install the latest:

in csproj:

<ItemGroup>
  <PackageReference Include="NLog.Web.AspNetCore" Version="5.*" />
  <PackageReference Include="NLog" Version="5.*" />
</ItemGroup>

2. Create a nlog.config file.

Create nlog.config (lowercase all) file in the root of your project.

We use this example:

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd"
      autoReload="true"
      throwConfigExceptions="true"
      internalLogLevel="Info"
      internalLogFile="c:\temp\internal-nlog-AspNetCore.txt">

  <!-- enable asp.net core layout renderers -->
  <extensions>
    <add assembly="NLog.Web.AspNetCore"/>
  </extensions>

  <!-- the targets to write to -->
  <targets>
    <!-- File Target for all log messages with basic details -->
    <target xsi:type="File" name="allfile" fileName="c:\temp\nlog-AspNetCore-all-${shortdate}.log"
            layout="${longdate}|${event-properties:item=EventId:whenEmpty=0}|${level:uppercase=true}|${logger}|${message} ${exception:format=tostring}" />

    <!-- File Target for own log messages with extra web details using some ASP.NET core renderers -->
    <target xsi:type="File" name="ownFile-web" fileName="c:\temp\nlog-AspNetCore-own-${shortdate}.log"
            layout="${longdate}|${event-properties:item=EventId:whenEmpty=0}|${level:uppercase=true}|${logger}|${message} ${exception:format=tostring}|url: ${aspnet-request-url}|action: ${aspnet-mvc-action}" />

    <!--Console Target for hosting lifetime messages to improve Docker / Visual Studio startup detection -->
    <target xsi:type="Console" name="lifetimeConsole" layout="${MicrosoftConsoleLayout}" />
  </targets>

  <!-- rules to map from logger name to target -->
  <rules>
    <!-- Suppress output from Microsoft framework when non-critical -->
    <logger name="System.*" finalMinLevel="Warn" />
    <logger name="Microsoft.*" finalMinLevel="Warn" />

    <!-- All logs, including from Microsoft -->
    <logger name="*" minlevel="Trace" writeTo="allfile" />

    <!-- Keep output from Microsoft.Hosting.Lifetime to console for fast startup detection -->
    <logger name="Microsoft.Hosting.Lifetime*" finalMinLevel="Info" writeTo="lifetimeConsole" />

    <logger name="*" minlevel="Trace" writeTo="ownFile-web" />
  </rules>
</nlog>

More details of the config file are here.

It is also possible to have the NLog-configuration in the appsettings.json-file. Then one doesn't need to maintain an additional XML-configuration file.

Notice that one might have to pay special attention to the Hosting Lifetime Startup Messages, if removing all other LoggingProviders (like Console) and only using NLog. As it can cause hosting environments (Visual Studio / Docker / Azure Container) to not see an application as started.

3. Update program.cs

Update the program.cs to include UseNLog()

using NLog;
using NLog.Web;

// Early init of NLog to allow startup and exception logging, before host is built
var logger = NLog.LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger();
logger.Debug("init main");

try
{
    var builder = WebApplication.CreateBuilder(args);

    // Add services to the container.
    builder.Services.AddControllersWithViews();

    // NLog: Setup NLog for Dependency injection
    builder.Logging.ClearProviders();
    builder.Host.UseNLog();

    var app = builder.Build();

    // Configure the HTTP request pipeline.
    if (!app.Environment.IsDevelopment())
    {
        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.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}");

    app.Run();
}
catch (Exception exception)
{
    // NLog: catch setup errors
    logger.Error(exception, "Stopped program because of exception");
    throw;
}
finally
{
    // Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
    NLog.LogManager.Shutdown();
}

4. Microsoft Logging Filters

The Microsoft Logging filters specified in appsettings.json are ignored by default when using NLog 5.0. Just make sure that NLog configuration rules are configured correctly using finalMinLevel:

<rules>
    <logger name="System.*" finalMinLevel="Warn" />
    <logger name="Microsoft.*" finalMinLevel="Warn" />
    <logger name="Microsoft.Hosting.Lifetime*" finalMinLevel="Info" />
    <logger name="*" minlevel="Trace" writeTo="ownFile-web" />
</rules>

It is possible to configure NLog LoggingProvider to obey the Microsoft filters specified in appsettings.json-file, by specifying RemoveLoggerFactoryFilter = false when calling UseNLog(...). Notice it is also possible to have the NLog configuration in the appsettings.json.

{
  "Logging": {
    "LogLevel": {
      "Default": "Trace",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    },
    "NLog": {
      "RemoveLoggerFactoryFilter": true
    }
  },
  "AllowedHosts": "*"
}

Remember to also update any environment specific configuration to avoid any surprises. Ex appsettings.Development.json

5. Write logs

Inject the ILogger in your controller:

using Microsoft.Extensions.Logging;

public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;

    public HomeController(ILogger<HomeController> logger)
    {
        _logger = logger;
        _logger.LogDebug(1, "NLog injected into HomeController");
    }

    public IActionResult Index()
    {
        _logger.LogInformation("Hello, this is the index!");
        return View();
    }
}

6. Example Output

When starting the ASP.NET Core website, we get two files:

nlog-own-2025-11-15.log (partial)

2025-11-15 22:33:24.7160|0|DEBUG|NLog_Web_Example.Program|init main |url: |action: 
2025-11-15 22:33:25.3384|63|INFO|Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager|User profile is available. Using 'C:\Users\David\AppData\Local\ASP.NET\DataProtection-Keys' as key repository and Windows DPAPI to encrypt keys at rest. |url: |action: 
2025-11-15 22:33:25.5106|14|INFO|Microsoft.Hosting.Lifetime|Now listening on: https://localhost:7080 |url: |action: 
2025-11-15 22:33:25.5144|14|INFO|Microsoft.Hosting.Lifetime|Now listening on: http://localhost:5123 |url: |action: 
2025-11-15 22:33:25.5543|0|INFO|Microsoft.Hosting.Lifetime|Application started. Press Ctrl+C to shut down. |url: |action: 
2025-11-15 22:33:25.5543|0|INFO|Microsoft.Hosting.Lifetime|Hosting environment: Development |url: |action: 
2025-11-15 22:33:25.5543|0|INFO|Microsoft.Hosting.Lifetime|Content root path: C:\workspace\projects\NLog_Web_Example\NLog_Web_Example |url: |action: 
2025-11-15 22:33:27.7618|1|INFO|Microsoft.AspNetCore.Hosting.Diagnostics|Request starting HTTP/2 GET https://localhost:7080/ - - - |url: https://localhost/|action: 
2025-11-15 22:33:27.8688|0|INFO|Microsoft.AspNetCore.Routing.EndpointMiddleware|Executing endpoint 'NLog_Web_Example.Controllers.HomeController.Index (NLog_Web_Example)' |url: https://localhost/|action: Index
2025-11-15 22:33:27.8979|102|INFO|Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker|Route matched with {action = "Index", controller = "Home"}. Executing controller action with signature Microsoft.AspNetCore.Mvc.IActionResult Index() on controller NLog_Web_Example.Controllers.HomeController (NLog_Web_Example). |url: https://localhost/|action: Index
2025-11-15 22:33:27.8979|1|DEBUG|NLog_Web_Example.Controllers.HomeController|NLog injected into HomeController |url: https://localhost/|action: Index
2025-11-15 22:33:27.8979|0|INFO|NLog_Web_Example.Controllers.HomeController|Hello, this is the index! |url: https://localhost/|action: Index
2025-11-15 22:33:27.9062|1|INFO|Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor|Executing ViewResult, running view Index. |url: https://localhost/|action: Index
2025-11-15 22:33:27.9775|4|INFO|Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor|Executed ViewResult - view Index executed in 70.015ms. |url: https://localhost/|action: Index
2025-11-15 22:33:27.9775|105|INFO|Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker|Executed action NLog_Web_Example.Controllers.HomeController.Index (NLog_Web_Example) in 79.9648ms |url: https://localhost/|action: Index
2025-11-15 22:33:27.9775|1|INFO|Microsoft.AspNetCore.Routing.EndpointMiddleware|Executed endpoint 'NLog_Web_Example.Controllers.HomeController.Index (NLog_Web_Example)' |url: https://localhost/|action: Index
2025-11-15 22:33:27.9868|1|INFO|Microsoft.AspNetCore.Hosting.Diagnostics|Request starting HTTP/2 GET https://localhost:7080/_framework/aspnetcore-browser-refresh.js - - - |url: https://localhost/_framework/aspnetcore-browser-refresh.js|action: 
2025-11-15 22:33:27.9868|2|INFO|Microsoft.AspNetCore.Hosting.Diagnostics|Request finished HTTP/2 GET https://localhost:7080/ - 200 - text/html;+charset=utf-8 231.7421ms |url: https://localhost/|action: Index

nlog-all-2021-11-15.log

2025-11-15 22:33:24.7160|0|DEBUG|NLog_Web_Example.Program|init main 
2025-11-15 22:33:25.3384|63|INFO|Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager|User profile is available. Using 'C:\Users\David\AppData\Local\ASP.NET\DataProtection-Keys' as key repository and Windows DPAPI to encrypt keys at rest. 
2025-11-15 22:33:25.5106|14|INFO|Microsoft.Hosting.Lifetime|Now listening on: https://localhost:7080 
2025-11-15 22:33:25.5144|14|INFO|Microsoft.Hosting.Lifetime|Now listening on: http://localhost:5123 
2025-11-15 22:33:25.5543|0|INFO|Microsoft.Hosting.Lifetime|Application started. Press Ctrl+C to shut down. 
2025-11-15 22:33:25.5543|0|INFO|Microsoft.Hosting.Lifetime|Hosting environment: Development 
2025-11-15 22:33:25.5543|0|INFO|Microsoft.Hosting.Lifetime|Content root path: C:\workspace\projects\NLog_Web_Example\NLog_Web_Example 
2025-11-15 22:33:27.7618|1|INFO|Microsoft.AspNetCore.Hosting.Diagnostics|Request starting HTTP/2 GET https://localhost:7080/ - - - 
2025-11-15 22:33:27.8688|0|INFO|Microsoft.AspNetCore.Routing.EndpointMiddleware|Executing endpoint 'NLog_Web_Example.Controllers.HomeController.Index (NLog_Web_Example)' 
2025-11-15 22:33:27.8979|102|INFO|Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker|Route matched with {action = "Index", controller = "Home"}. Executing controller action with signature Microsoft.AspNetCore.Mvc.IActionResult Index() on controller NLog_Web_Example.Controllers.HomeController (NLog_Web_Example). 
2025-11-15 22:33:27.8979|1|DEBUG|NLog_Web_Example.Controllers.HomeController|NLog injected into HomeController 
2025-11-15 22:33:27.8979|0|INFO|NLog_Web_Example.Controllers.HomeController|Hello, this is the index! 
2025-11-15 22:33:27.9062|1|INFO|Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor|Executing ViewResult, running view Index. 
2025-11-15 22:33:27.9775|4|INFO|Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor|Executed ViewResult - view Index executed in 70.015ms. 
2025-11-15 22:33:27.9775|105|INFO|Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker|Executed action NLog_Web_Example.Controllers.HomeController.Index (NLog_Web_Example) in 79.9648ms 
2025-11-15 22:33:27.9775|1|INFO|Microsoft.AspNetCore.Routing.EndpointMiddleware|Executed endpoint 'NLog_Web_Example.Controllers.HomeController.Index (NLog_Web_Example)' 
2025-11-15 22:33:27.9868|1|INFO|Microsoft.AspNetCore.Hosting.Diagnostics|Request starting HTTP/2 GET https://localhost:7080/NLog_Web_Example.styles.css?v=9PR-gDBjbkKzRjUd3-K6kxqs7TXxvL9PMushXIjPL_8 - - - 
2025-11-15 22:33:27.9868|1|INFO|Microsoft.AspNetCore.Hosting.Diagnostics|Request starting HTTP/2 GET https://localhost:7080/_framework/aspnetcore-browser-refresh.js - - - 
2025-11-15 22:33:27.9868|2|INFO|Microsoft.AspNetCore.Hosting.Diagnostics|Request finished HTTP/2 GET https://localhost:7080/ - 200 - text/html;+charset=utf-8 231.7421ms 
2025-11-15 22:33:27.9868|6|INFO|Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware|The file /NLog_Web_Example.styles.css was not modified 
2025-11-15 22:33:27.9961|2|INFO|Microsoft.AspNetCore.Hosting.Diagnostics|Request finished HTTP/2 GET https://localhost:7080/NLog_Web_Example.styles.css?v=9PR-gDBjbkKzRjUd3-K6kxqs7TXxvL9PMushXIjPL_8 - 304 - text/css 9.3790ms 
2025-11-15 22:33:27.9961|1|INFO|Microsoft.AspNetCore.Hosting.Diagnostics|Request starting HTTP/2 GET https://localhost:7080/_vs/browserLink - - - 
2025-11-15 22:33:27.9961|2|INFO|Microsoft.AspNetCore.Hosting.Diagnostics|Request finished HTTP/2 GET https://localhost:7080/_framework/aspnetcore-browser-refresh.js - 200 13768 application/javascript;+charset=utf-8 17.5225ms 
2025-11-15 22:33:28.0496|2|INFO|Microsoft.AspNetCore.Hosting.Diagnostics|Request finished HTTP/2 GET https://localhost:7080/_vs/browserLink - 200 - text/javascript;+charset=UTF-8 52.8898ms 

Configure NLog Targets for output

Next step, see Configure NLog with nlog.config

Clone this wiki locally