3

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?

monstertjie_za
  • 7,277
  • 8
  • 42
  • 73
  • Have you tried using `builder.RegisterType().As().SingleInstance();`? Obviously you need to register a logger and you should do it using the autofac builder and before you register your `EventComponent` class. – jegtugado Aug 28 '18 at 07:21
  • @JohnEphraimTugado What does Logger represent? I do not have a Logger class, and if I want to use the defualt Logger class provided by Intellisense, I need to pass a Type to the generic Logger class – monstertjie_za Aug 28 '18 at 07:23
  • You need to pass an implementation of `ILogger` which can be your own implementation. You can also check [this](https://stackoverflow.com/a/49112636/6138713) answer as reference. – jegtugado Aug 28 '18 at 07:30
  • Why are you even using an `ILogger` in your `EventComponent` class when you are not familiar with the `ILogger` itself? Is it not possible to remove the reference? – jegtugado Aug 28 '18 at 07:34
  • @JohnEphraimTugado the .NET SDK provides a default implementation for ILogger, which Logs to Application Insights, and I would like to make use of the default logging in my component class. – monstertjie_za Aug 28 '18 at 07:41
  • Then you should register that default implementation for `ILogger` using autofac builder. – jegtugado Aug 28 '18 at 07:42

3 Answers3

2

In Azure Functions V2, the ILogger is injected by default. Also, here are two very nice articles on dependency inject in Azure Functions. https://blog.mexia.com.au/dependency-injections-on-azure-functions-v2

and http://codingsoul.de/2018/01/19/azure-function-dependency-injection-with-autofac/

Gaurav Madaan
  • 459
  • 5
  • 9
0

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.

SamiR
  • 77
  • 10
0

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);
         }
     }
    
Dawie Snyman
  • 87
  • 1
  • 1