How to access ILogger in all classes in Azure Function running on .NET Core 6 isolated

97 Views Asked by At

I'm converting a web job to an Azure Function. I created an Azure Function with .NET 6 isolated. I'm unable to access the ILogger from class constructor, getting this error:

System.InvalidOperationException: Unable to resolve service for type 'Microsoft.Extensions.Logging.LoggerFactory' while attempting to activate 'ABC'

Here is my code:

namespace MyFunction
{
    public class MyFunctionProcessor
    {
        private readonly ILogger log;
        private IABC _iABC;

        public MyFunctionProcessor(ILoggerFactory logger, IABC _iABC)
        {
            log = logger.CreateLogger<MyFunctionProcessor>();
            this._iABC = _iABC;
        }

        [Function(nameof(MyFunctionProcessor))]
        public async Task Run([EventHubTrigger("%EventHubName%", 
            Connection = "ServiceBusConnectionString")] EventData[] events, PartitionContext partitionContext)
        {
            Guid correlationId = Guid.NewGuid();
            log.LogInformation($"CorrelationId: {correlationId} ABC Processor Function has been started");

            try
            {
                await this._iABC.SyncDataAsync(events, partitionContext);
            }
            catch (Exception ex)
            {
                log.LogError($"CorrelationId: {correlationId} Exception while processing the event {ex.Message} => {ex.StackTrace}");
            }
        }
    }
}

ABC class file:

namespace MyFunction.Services
{
    public class ABC : IABC
    {
         private IService serv;
         private ILogger log;

         public ABC(IService _serv, LoggerFactory _log)
         {
              serv = _serv;
              log =_log.CreateLogger<ABC>();
         }
         
          public async Task SyncDataAsync(EventData[] messages, PartitionContext context)
          {
              // code logic
              var xyz = serv.getDetails();          
              // code logic
          }
    }
}

Program.cs file:

var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults()
.ConfigureServices(services =>
{
    services.AddApplicationInsightsTelemetryWorkerService();
    services.ConfigureFunctionsApplicationInsights();
    services.AddScoped<IABC, ABC>();
    services.AddScoped<IService, Service>();
    services.AddLogging();
    services.AddSingleton<ILoggerFactory, LoggerFactory>();
    services.AddSingleton(typeof(ILogger<>), typeof(Logger<>));
})
.Build();

host.Run();

Class library service code:

namespace ClassLibrary1
{
    public class Service : IService
    {
         private ILogger log;

         public Service(LoggerFactory _log)
         {
              log =_log.CreateLogger<Service>();
         }
         
         public async Task getDetails()
         {
             // code logic
             // here I'm logging the details
         }
    }
}

How can I resolve this?

1

There are 1 best solutions below

2
Andrew S On

An ILoggerFactory was registered for dependency injection (DI). But ABC's constructor

public ABC(IService _serv, LoggerFactory _log)
{
     serv = _serv;
     log =_log.CreateLogger<ABC>();
}

requires a LoggerFactory. That constructor parameter type would need to be changed to ILoggerFactory.

However, the use of ILoggerFactory isn't required. An ILogger<T> will be available for DI, so the use of the factory within the constructor can be avoided. For example, ABC's constructor could be changed to:

private readonly ILogger<ABC> _logger;
public ABC(IService _serv, ILogger<ABC> logger)
{
     serv = _serv;
     _logger = logger;
}

This might also be helpful.