Christian Schou
  • Home
  • Blog
    • Programming
      • C#
      • PowerShell
      • Python
      • SQL
    • WordPress
      • Tutorials
    • Cloud
    • Home Automation
      • Home Assistant
        • Node-Red
    • Career
  • Services
  • Glossary
  • About
No Result
View All Result
Christian Schou
  • Home
  • Blog
    • Programming
      • C#
      • PowerShell
      • Python
      • SQL
    • WordPress
      • Tutorials
    • Cloud
    • Home Automation
      • Home Assistant
        • Node-Red
    • Career
  • Services
  • Glossary
  • About
No Result
View All Result
Christian Schou
No Result
View All Result
Home Programming C#

How to log events on ASP.NET Core Web API with NLog (.NET 5.0)

by Christian
16. September 2021
in C#
0

During development, logging (maybe with NLog) is a crucial part – but why? While you develop your application it’s easy to debug, set breakpoints, and test small features to figure out where the issues are. Have you thought about what happens if you would like to debug in a production environment?

It’s not possible… And here the logging comes into the picture. They help us figure out what is wrong with our code when running in production mode. Errors happen – we can’t get around that. By default, .NET Core has a built-in implementation for handling the logging of messages. Though in all projects I make I prefer to create my own custom logger service that can be extended per my needs.

This project builds on a solution I made in my previous post > How to configure ASP.NET Core Web API .NET Core Service Configuration – It’s just a .NET Core API Solution.

Inhaltsverzeichnis
  1. Adding new projects for solution
  2. Install NLog and Create Interface
    • Add interface in Contracts
    • Install NLog package in LoggerService
      • Package Manager Console : LoggerService
      • NuGet Package Manager : LoggerService
    • Implementation of LoggerManager and NLog Configuration
    • Add NLog to Startup Configuration to enable logging of messages
  3. Dependency Injection, Inversion of Control and Testing og NLog
    • Testing the logger functionality
  4. Summary

Adding new projects for solution

For this tutorial, I will be adding two projects. The first one is called LoggerService, this will be responsible for logger logic. The second project is named Contracts and will hold interfaces to be used in the whole project.

Both projects are of the type Class Library (.NET Core). To create a new project Open your solution, right-click on the solution in your solution explorer, click Add and select New Project. In the popup window you have to select Class library for .NET Core.

Create a new project in solution

On the configuration page, leave the Location as the default set by Visual Studio and name the class library that you find suitable for the type of service. Click on Next, when done.

Configure New Project

By default .NET 5.0 should be selected for you, if no click the drop-down and select it. Finish up by click Create in the lower right corner.

Additional Information for project

Do the same thing for the Contracts project. When you have finished that task we need to configure references for the projects. Go back and right-click on the first project we created (NetApiCoreServer) and click on Add and Click on Project Reference. In the popup window select LoggerService as shown below:

Add Project Reference

Do the same thing for LoggerService. This time you have to add Contracts as a reference. This gives access to the main project since it got a reference to LoggerService.

Install NLog and Create Interface

Normally I add four logging methods by default to new projects. By default, our logger service should be able to log the following messages:

  • Info Messages
  • Debug Messages
  • Warning Messages
  • Error Messages

Add interface in Contracts

Go to your Contracts project and create a new interface named ILoggerManager. This should contain four method definitions as shown in the code below:

namespace Contracts
{
    public interface ILoggerManager
    {
        void LogInfo(string message);
        void LogWarning(string message);
        void LogDebug(string message);
        void LogError(string message);
    }
}

Before we make the actual implementation for this interface, we need to add the NLog library to our LoggerService project. In short – NLog is a logging platform for .NET which helps developers create and log messages from applications.

Install NLog package in LoggerService

Normally I would install the package through the Package Manager Console, but some of my readers have requested that I also show you how to install it from the GUI (NuGet Package Manager). Below is the command you have to execute in the Package Manager Console to install NLog.

Package Manager Console : LoggerService

Install-Package NLog.Extensions.Logging
nlog
Install with Package Manager Console

NuGet Package Manager : LoggerService

Right click on LoggerServices, select Manage NuGet Packages... to open up the NuGet Package Manager. Click on Browse and enter nlog.extensions.logging in the search field, select the first option and click Install.

nlog
NuGet Package Manager : LoggerService

After a short period of time, you now have the NLog library installed in the LoggerService project and you are good to go.

Implementation of LoggerManager and NLog Configuration

Now for the more fun part – Open up the LoggerService project and create a new class named LoggerManager to match the Interface we created in the Contracts project. Add the following code to the new LoggerManager Class:

using Contracts;
using NLog;

namespace LoggerService
{
    public class LoggerManager : ILoggerManager
    {
        private static ILogger logger = LogManager.GetCurrentClassLogger();
        public void LogDebug(string message)
        {
            logger.Debug(message);
        }
        public void LogError(string message)
        {
            logger.Error(message);
        }
        public void LogInfo(string message)
        {
            logger.Info(message);
        }
        public void LogWarning(string message)
        {
            logger.Warn(message);
        }
    }
}

For NLog to fully function it needs information about where it should create the log files, the naming convention, and the minimum level of logging for the application. To do this you have to create a new file in the main project with the name nlog.config and add the below code. You should change the path for the internal log and file name to match the configuration of your solution.

<?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"
      autoReload="true"
      internalLogLevel="Trace"
      internalLogFile="C:\Users\chs\source\repos\NetCoreApiServer\InternalLogs\internallog.txt">
  <targets>
    <target name="logfile" xsi:type="File"
            fileName="C:/Users/chs/source/repos/NetCoreApiServer/Logs/${shortdate}_logfile.txt"
            layout="${longdate} ${level:uppercase=true} ${message}"/>
  </targets>
  <rules>
    <logger name="*" minlevel="Debug" writeTo="logfile" />
  </rules>
</nlog>

With that in place, let’s go ahead and configure the log service in the main project.

Add NLog to Startup Configuration to enable logging of messages

It is very easy to set up logging for a service. The only thing we have to do is add this piece of code to our constructor in the Startup class.

public Startup(IConfiguration configuration)
{
    Configuration = configuration;    
    LogManager.LoadConfiguration(String.Concat(Directory.GetCurrentDirectory(), "/nlog.config"));
}

Then we have to add the logger service inside .NET Cores IOC container. You can accomplish this in multiple ways:

  1. Call services.AddSingleton – This will create a service the first time you request it and then every subsequent request is calling the same instance of the service. What this means is that all components of this is sharing the same service everytime they need it. You will always be using the same instance.
  2. Call services.AddScoped – This will create the service for every request made. That means whenever a user makes a request through HTTP, a new instance of the service is created.
  3. Call services.AddTransient – This created the service every time the application is requesting it. If you got one request against your application and multiple components need this service, then the service will be created again for each component.

Since our logging service always will be using the same service, let’s register it using a Singleton. Go to the ServiceExtensions class we created in the previous tutorial about the configuration of .NET Core Service Configuration and append the following code to the end of the class.

public static void ConfigureNLogService(this IServiceCollection services)
{
    services.AddSingleton<ILoggerManager, LoggerManager>();
}

Don’t forget to register this configuration in ConfigureServices in the Startup class to invoke the logger method. Add the short piece of code shown below:

public void ConfigureServices(IServiceCollection services)
{

    services.ConfigureCors();
    services.ConfigureIISIntegration();
    services.ConfigureNLogService();

    services.AddControllers();
    services.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("v1", new OpenApiInfo { Title = "NetCoreApiServer", Version = "v1" });
    });
}

Awesome – now the only thing we have to do is to inject the logger service into the constructor of the class that we would like to use logging at. .NET Core will give us the logger service through the IOC container including its features. This is also referred to as Dependency Injection.

Dependency Injection, Inversion of Control and Testing og NLog

Well, I have been mentioning IOC a few times in this article – for beginners IOC is short for Inversion of Control and DI is short for Dependency Injection and you will often meet these teams in the development community. But what are they? Everybody is talking about them but no one is saying exactly what they are.

Ever heart about loose coupling? Dependency Injection is a technique a developer can use to achieve that – they get a loose coupling between objects and their dependencies. In other words – Instead of instantiating an object every time it’s needed, we can do it only one time and then serve it within a class, often through the constructor of that specific class.

If the system is designed to make use of DI, you may find that the classes are requesting their dependencies through the constructor. If that’s the case it’s a good idea to have a class that can give access to all classes through the constructor. These classes are very often referred to as containers or what I call Inversion of Control containers. You can see the container as a factory responsible for allowing access to instances of types that are requested from that specific container.

In this project, I will make a constructor injection on the WeatherForecastController to make use of the LoggerService. This is the default controller created by the project creator and will be available in the Controllers folder. Add the following code to use the NLog service and log values to the files at the location we specified in nlog.config.

using Contracts;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;

namespace NetCoreApiServer.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class WeatherForecastController : ControllerBase
    {
        private static readonly string[] Summaries = new[]
        {
            "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
        };

        private readonly ILoggerManager _logger;

        public WeatherForecastController(ILoggerManager logger)
        {
            _logger = logger;
        }

        [HttpGet]
        public IEnumerable<string> WriteLogs()
        {
            _logger.LogInfo("Here is info message from the controller.");
            _logger.LogDebug("Here is debug message from the controller.");
            _logger.LogWarning("Here is warn message from the controller.");
            _logger.LogError("Here is error message from the controller.");
            return new string[] { "value1", "value2" };
        }

        [HttpGet]
        public IEnumerable<WeatherForecast> Get()
        {
            var rng = new Random();
            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = rng.Next(-20, 55),
                Summary = Summaries[rng.Next(Summaries.Length)]
            })
            .ToArray();
        }
    }
}

Testing the logger functionality

Okay so now all the configuration has been made – it’s time for testing. Start the application and go to Swagger (should open by default) and request the endpoint WriteLogs at the WeatherForecastController.

Request Write Logs Endpoint in Swagger

Success – we got the two values back that we implemented in the controller action. Go and check the location for the log files to see, if you have a log file from the request. The result inside the file should look like the following:

2021-09-16 17:14:46.2747 INFO Here is info message from the controller.
2021-09-16 17:14:46.3399 DEBUG Here is debug message from the controller.
2021-09-16 17:14:46.3551 WARN Here is warn message from the controller.
2021-09-16 17:14:46.3670 ERROR Here is error message from the controller.

Summary

Now we got a fully functioning logger service that will be available at all classes through dependency injection. We have talked about why logging is an important thing to do, how you can create an external service for the logger, how to use NLog, and the setup of the configuration for NLog. Very briefly have I talked about Dependency Injection and Inversion of Control and how you inject a service.

Thank you for reading this tutorial. I will In the next tutorial about logging teach you how to log the events to an MS SQL database – which makes it easier in the future to sort events and present them in a Dashboard through the controller. More on that later – Happy coding!

Tags: .NET 5.0.Net CoreAPIASP.NET CoreLoggingNLogWeb
Previous Post

How to configure ASP.NET Core Web API .NET Core Service Configuration

Next Post

How to use Dapper with ASP.NET Core and Repository Pattern

Christian

Christian

Hello 👋 My name is Christian and I am 26 years old. I'm an educated Software Developer with a primary focus on C#, .NET Core, Python, and PowerShell. Currently, I'm expanding my skills in Software Robots and Cloud Architecture. In some of my spare time, I share my knowledge about tech stuff on my blog.

Related Posts

watchdog
ASP.NET Core

The #1 guide to show real-time .NET 6 logs for Web Apps and APIs in a modern way using WatchDog for Free

by Christian
13. August 2022
0

A reader recently asked me for a more modern way to view log files for requests and exceptions in a...

Read more
restful web api

How to build a RESTful Web API using ASP.NET Core and Entity Framework Core (.NET 6)

25. Juli 2022
dynamically register entities

How to Dynamically Register Entities in DbContext by Extending ModelBuilder?

23. Juli 2022
Dockerize ASP.NET Core

How to Compose an ASP.NET Core Web API (.NET 6) with an MS SQL Server 2022 on Linux in Docker

19. Juli 2022
pattern matching in switch

How to do pattern matching in switch statements – C# version >= 7.0

11. Juli 2022
Next Post
dapper

How to use Dapper with ASP.NET Core and Repository Pattern

Christian Schou

Christian Schou

Software Developer

Hello - my name is Christian and I am 26 years old. I'm an educated Software Developer with a primary focus on C#, .NET Core, Python, and PowerShell. Currently, I'm expanding my skills in Software Robots and Cloud Architecture. In some of my spare time, I share my knowledge about tech stuff on my blog.

Recent articles

personal website
Career

Top 6 things to add on your personal website to get hired for a tech job

by Christian
7. August 2022
0

Back in the days before the internet was a thing like it is today, we used to have business cards...

Read more
watchdog

The #1 guide to show real-time .NET 6 logs for Web Apps and APIs in a modern way using WatchDog for Free

13. August 2022
get hired for a tech job

5 tips to help you get hired for a tech job

31. Juli 2022
restful web api

How to build a RESTful Web API using ASP.NET Core and Entity Framework Core (.NET 6)

25. Juli 2022
dynamically register entities

How to Dynamically Register Entities in DbContext by Extending ModelBuilder?

23. Juli 2022

Christian Schou

Software Developer

Hello - my name is Christian and I am 26 years old. I'm an educated Software Developer with a primary focus on C#, .NET Core, Python, and PowerShell. Currently, I'm expanding my skills in Software Robots and Cloud Architecture. In some of my spare time, I share my knowledge about tech stuff on my blog.

Recent articles

personal website

Top 6 things to add on your personal website to get hired for a tech job

7. August 2022
watchdog

The #1 guide to show real-time .NET 6 logs for Web Apps and APIs in a modern way using WatchDog for Free

13. August 2022
get hired for a tech job

5 tips to help you get hired for a tech job

31. Juli 2022
  • de_DEDeutsch
    • da_DKDansk
    • en_USEnglish
    • hi_INहिन्दी
    • pt_BRPortuguês do Brasil
  • Contact
  • Datenschutzrichtlinie
  • Nutzungsbedingungen

© 2022 Christian Schou - All rights reserved.

No Result
View All Result
  • Home
  • Blog
    • Programming
      • C#
      • PowerShell
      • Python
      • SQL
    • WordPress
      • Tutorials
    • Cloud
    • Home Automation
      • Home Assistant
    • Career
  • Services
  • Glossary
  • About

© 2022 Christian Schou - All rights reserved.

I use cookies on my website to give you the most relevant experience by remembering your preferences and repeat visits. By clicking “Accept”, you consent to the use of ALL the cookies.
Do not sell my personal information.
Cookie settingsACCEPT
Privacy & Cookies Policy

Privacy Overview

This website uses cookies to improve your experience while you navigate through the website. Out of these cookies, the cookies that are categorized as necessary are stored on your browser as they are essential for the working of basic functionalities of the website. We also use third-party cookies that help us analyze and understand how you use this website. These cookies will be stored in your browser only with your consent. You also have the option to opt-out of these cookies. But opting out of some of these cookies may have an effect on your browsing experience.
Necessary
immer aktiv
Necessary cookies are absolutely essential for the website to function properly. This category only includes cookies that ensures basic functionalities and security features of the website. These cookies do not store any personal information.
Functional
Functional cookies help to perform certain functionalities like sharing the content of the website on social media platforms, collect feedbacks, and other third-party features.
Performance
Performance cookies are used to understand and analyze the key performance indexes of the website which helps in delivering a better user experience for the visitors.
Analytics
Analytical cookies are used to understand how visitors interact with the website. These cookies help provide information on metrics the number of visitors, bounce rate, traffic source, etc.
CookieDauerBeschreibung
__gads1 year 24 daysThe __gads cookie, set by Google, is stored under DoubleClick domain and tracks the number of times users see an advert, measures the success of the campaign and calculates its revenue. This cookie can only be read from the domain they are set on and will not track any data while browsing through other sites.
_ga2 yearsThe _ga cookie, installed by Google Analytics, calculates visitor, session and campaign data and also keeps track of site usage for the site's analytics report. The cookie stores information anonymously and assigns a randomly generated number to recognize unique visitors.
_ga_0J2F6JVWSD2 yearsThis cookie is installed by Google Analytics.
_gat_gtag_UA_84232734_11 minuteSet by Google to distinguish users.
_gid1 dayInstalled by Google Analytics, _gid cookie stores information on how visitors use a website, while also creating an analytics report of the website's performance. Some of the data that are collected include the number of visitors, their source, and the pages they visit anonymously.
YouTube2 yearsYouTube sets this cookie via embedded youtube-videos and registers anonymous statistical data. I embed YouTube videos in my articles/tutorials - you won't get the full experience of the articles if this is deactivated.
Advertisement
Advertisement cookies are used to provide visitors with relevant ads and marketing campaigns. These cookies track visitors across websites and collect information to provide customized ads.
CookieDauerBeschreibung
IDE1 year 24 daysGoogle DoubleClick IDE cookies are used to store information about how the user uses the website to present them with relevant ads and according to the user profile.
test_cookie15 minutesThe test_cookie is set by doubleclick.net and is used to determine if the user's browser supports cookies.
VISITOR_INFO1_LIVE5 months 27 daysA cookie set by YouTube to measure bandwidth that determines whether the user gets the new or old player interface.
YSCsessionYSC cookie is set by Youtube and is used to track the views of embedded videos on Youtube pages.
yt-remote-connected-devicesneverYouTube sets this cookie to store the video preferences of the user using embedded YouTube video.
yt-remote-device-idneverYouTube sets this cookie to store the video preferences of the user using embedded YouTube video.
Others
Other uncategorized cookies are those that are being analyzed and have not been classified into a category as yet.
SPEICHERN & AKZEPTIEREN
Unterstützt von CookieYes Logo