Dudeman3000
Dudeman3000

Reputation: 601

.Net Core Logging Dependency Injection - resolve ILogger / ILogger`1 - what does the tick mean? Resolve type possible?

I'm working with a .Net Core 3.1 XUnit project.

I create a SerivceCollection and call the AddLogging extension method. Then I can create an ILogger instance with the LoggerFactory / ILoggerFactory and when I debug, I can my ServiceCollection has a ServiceDescriptor for this type:

Lifetime = Singleton, ServiceType = {Name = "ILogger`1" FullName = "Microsoft.Extensions.Logging.ILogger`1"}, ImplementationType = {Name = "Logger`1" FullName = "Microsoft.Extensions.Logging.Logger`1"}

I'm curious what that tick mark means in the type name and if it's possible to resolve an ILogger instance without using the LoggerFactory.

Here are a couple failed attempts at resolving ILogger`1. The last call to CreateLogger works.

[Fact]
        public void AddLogging_RegistersILogger()
        {
            var services = new ServiceCollection().AddLogging();

            var serviceProvider = services.BuildServiceProvider();

            var logger1 = serviceProvider.GetService<ILogger>(); // logger == null

            try
            {
                var logger2 = serviceProvider.GetService(typeof(ILogger<>));
            }
            catch (Exception e)
            {
                // Implementation type 'Microsoft.Extensions.Logging.Logger`1[T]' can't be converted to service type 'Microsoft.Extensions.Logging.ILogger`1[TCategoryName]'
            }

            try
            {
                var loggerTypes = Assembly.GetAssembly(typeof(ILogger)).GetTypes().Where(t => t.Name == "ILogger`1");
                var loggerType = loggerTypes.First();
                var logger3 = serviceProvider.GetService(loggerType);
            }
            catch(Exception e)
            {
                // Implementation type 'Microsoft.Extensions.Logging.Logger`1[T]' can't be converted to service type 'Microsoft.Extensions.Logging.ILogger`1[TCategoryName]'
            }

            var logger4 = serviceProvider.GetService<ILoggerFactory>().CreateLogger<DependencyInjectionTests>();

            Assert.NotNull(logger4);
        }

Upvotes: 4

Views: 6679

Answers (2)

I resolved the problem by implemented NLog using the following steps in asp.net core

https://code-maze.com/net-core-web-development-part3/

Nuget:
1. NLog.Config
2. NLog.Extensions.Logging

Logging

functionality added to software so someone can get insight into the software

Logging as targets and rules.

nlog.config (change property to copy always)

1. the logfile name creates a file in the logs directory
2. debug is wrote to the logfile target

<?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="internallog.txt">
  <targets>
    <target name="logfile" xsi:type="File"
            fileName="${startupdir}\logs\${shortdate}_logfile.txt"
            layout="${longdate} ${level:uppercase=true} ${message}"/>
  </targets>
  <rules>
    <logger name="*" minlevel="Debug" writeTo="logfile" />
  </rules>
</nlog>

startup.cs

1. load the nlog.config
2. ConfigureLoggerService is part of the static class called Service Extensions.  Its job is to create a singleton task for the LoggerManager

public Startup(IConfiguration configuration)
        {
            LogManager.LoadConfiguration(@"nlog.config");
            Configuration = configuration;
            //_env = env;
        }

        public void ConfigureServices(IServiceCollection services)
        {
services.ConfigureLoggerService();
    }

serviceExtensions.cs

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

LoggerManager.cs

1. use the dependency injected Logger for nLog to post based on type.

 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 LogWarn(string message)
        {
            logger.Warn(message);
        }
    }

Upvotes: 0

Michael Shterenberg
Michael Shterenberg

Reputation: 1016

The tick on "ILogger`1" means its a generic type, i.e. ILogger<CategoryName>

You can inject ILogger<T> for any generic type. The generic type is used to set the category name in a convenient manner, e.g. ILogger<Controller> will have "Microsoft.AspNetCore.Mvc.Controller" category name

The common practice is for each class to have a logger with the category name of the class, e.g. a class namedMyService will have a logger ILogger<MyService>

You can either inject ILogger<T> or use ILoggerFactory:

  • Injecting ILogger<MyService> is equivalent to calling loggerFactory.CreateLogger<MyService>() or loggerFactory.CreateLogger("<namespace_of_my_service>.MyService")

Upvotes: 4

Related Questions