Inject instance of ILogger in my component class Azure Functions using Autofac

Viewed 3438

I am writing a simple Azure function.

I have installed the AzureFunctions.Autofac nuget package, and would like to use this as my DI library.

I have set up the following AutofacConfig class to register my types:

public class AutofacConfig
{
    public AutofacConfig(string functionName)
    {
        DependencyInjection.Initialize(builder =>
        {
            //do all of you initialization here

            //db client
            builder.RegisterType<EventComponent>()
            .As<IComponent<EventModel>>().SingleInstance(); 
        }, functionName);
    }
}

Here is my EventComponent class, to which I would like to inject the ILogger instance provided.

public class EventComponent : IComponent<EventModel>
{
    private ILogger _log;

    public EventComponent(ILogger logger)
    {
        _log = logger;
    }
}

Here is how I inject my EventComponent:

[FunctionName("AddEvent")]
    public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "post", Route = null)]HttpRequestMessage req, ILogger log, [Inject]IComponent<EventModel> component)
    {
        log.LogInformation("C# HTTP trigger function processed a request.");

        await component.Add(new EventModel() { Id = Guid.NewGuid(), Description = $"Test description nr: {new Random().Next(1, 100000)}", User = "Test User" });

        return req.CreateResponse(HttpStatusCode.OK);
    }

The problem is, I get an exception on the above, because Autofac cannot resolve the parameter Microsoft.Extensions.Logging.ILogger.

Here is the exception message:

Exception binding parameter 'component'... Cannot resolve parameter 'Microsoft.Extensions.Logging.ILogger logger' of constructor 'Void .ctor(Microsoft.Extensions.Logging.ILogger)'. (See inner exception for details.) -> None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'Event.Function.Components.EventComponent' can be invoked with the available services and parameters:\r\nCannot resolve parameter 'Microsoft.Extensions.Logging.ILogger logger' of constructor 'Void .ctor(Microsoft.Extensions.Logging.ILogger)'.",

How can I inject the ILogger instance into my EventComponent class?

3 Answers

I found your question when looking for the same thing. Have you found a solution?

Because I don't think that is possible. ILogger log is injected by the framework and I don't see how it could be referenced from your AutofacConfig-class.

How I resolved this was by changing the EventComponent-class to use Setter-injection instead of Constructor-injection, like this:

public class EventComponent : IComponent<EventModel>
{
    public ILogger Log { get; set; }    
}

and change your function to set the Log-property:

[FunctionName("AddEvent")]
    public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "post", Route = null)]HttpRequestMessage req, ILogger log, [Inject]IComponent<EventModel> component)
    {
        log.LogInformation("C# HTTP trigger function processed a request.");
        component.Log = log;
        await component.Add(new EventModel() { Id = Guid.NewGuid(), Description = $"Test description nr: {new Random().Next(1, 100000)}", User = "Test User" });

        return req.CreateResponse(HttpStatusCode.OK);
    }

The downside is that you need to remember to set that value at the start of every function that uses that class, but the injection works.

If you want to inject the ILogger into a function app you need to do the following:

  1. Add the correct log level and namespace to your host.json

     {
        "version": "2.0",
        "logging": {
             "applicationInsights": {
                 "samplingSettings": {
                     "isEnabled": true
           }
         },
        "logLevel": {
            "YourNameSpace": "Information"
     }    
    
  2. Inject ILogger<T> where T is your function app class name/type. In this sample my function app class name is Api.

     public class TestService : ITestService
     {
         private readonly ILogger<Api> _logger;
    
         public TestService(ILogger<Api> logger)
         {
             _logger = logger;
         }
    
         public void LogSomething(string message)
         {
             _logger.LogInformation(message);
         }
     }
    
Related