Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ILogger injected via constructor for Http trigger functions with Azure Function 2.x

ILogger can be injected to function parameter, like Token method below.

However, the error below occurred when it is injected to constructor parameter log.

[07/03/2019 17:15:17] Executed 'Token' (Failed, Id=4e22b21f-97f0-4ab4-8f51-8651b 09aedc8) [07/03/2019 17:15:17] Microsoft.Extensions.DependencyInjection.Abstractions: Una ble to resolve service for type 'Microsoft.Extensions.Logging.ILogger' while attempting to activate 'Functions'.

ILogger can be injected to Token function parameter below. But the error above occurred when it is injected to constructor parameter log.

public class Functions
{
    private HttpClient _httpClient;
    private IAppSettings _appSettings;
    private ILogger _log;

    public Functions(HttpClient httpClient, IAppSettings appSettings  //working for these two
      , ILogger log  //not working, errors
    )
    {

        _log = log;
    }

    [FunctionName("Token")]
    public async Task<IActionResult> Token(
        [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "Token")]
        HttpRequest httpRequest,
        ILogger log)
    {

    }
}

Dependence injection below

[assembly: WebJobsStartup(typeof(Startup))]
namespace MyApp
{
    public class Startup : IWebJobsStartup
    {
        public void Configure(IWebJobsBuilder builder)
        {
            builder.Services.AddHttpClient();
            builder.Services.AddTransient<IAppSettings, AppSettings>();     
             //builder.Services.AddLogging();  //not working
           //builder.Services.AddSingleton<ILogger>() //not working
        }
}

Visual studio 2017

like image 927
Pingpong Avatar asked Mar 07 '19 17:03

Pingpong


People also ask

Can you trigger an Azure function using an HTTP request?

The HTTP trigger lets you invoke a function with an HTTP request. You can use an HTTP trigger to build serverless APIs and respond to webhooks. The default return value for an HTTP-triggered function is: HTTP 204 No Content with an empty body in Functions 2.

How run HTTP trigger Azure function in Visual Studio?

To start your function in Visual Studio in debug mode: Press F5. If prompted, accept the request from Visual Studio to download and install Azure Functions Core (CLI) tools. You might also need to enable a firewall exception so that the tools can handle HTTP requests.

Can Azure function have two triggers?

An Azure function can have multiple triggers, but the function must be explicitly configured to use multiple triggers. The Azure function can have a single trigger, or it can have multiple triggers.


2 Answers

I had this problem as well. I was able to fix it by calling AddLogging():

[assembly: WebJobsStartup(typeof(Startup))]
namespace MyApp
{
    public class Startup : IWebJobsStartup
    {
        public void Configure(IWebJobsBuilder builder)
        {
            builder.Services.AddHttpClient();
            builder.Services.AddTransient<IAppSettings, AppSettings>();     
            builder.Services.AddLogging();
        }
}

And then, in the Azure Function, I had to do pass a ILoggerFactory instead of an ILogger and get the ILogger instance from the loggerFactory:

public class Functions
{
    private HttpClient _httpClient;
    private IAppSettings _appSettings;
    private ILogger _log;

    public Functions(HttpClient httpClient, IAppSettings appSettings, ILoggerFactory loggerFactory)
    {
        _log = loggerFactory.CreateLogger<Functions>();
    }

    [FunctionName("Token")]
    public async Task<IActionResult> Token(
        [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "Token")]
        HttpRequest httpRequest)
    {
           // No need to keep getting the ILogger from the Run method anymore :)
    }
}
like image 86
Kzrystof Avatar answered Oct 20 '22 00:10

Kzrystof


Calling LogCategories.CreateFunctionUserCategory fixed my problem. Complete example:

Azure Functions Core Tools (2.7.1158 Commit hash: f2d2a2816e038165826c7409c6d10c0527e8955b)
Function Runtime Version: 2.0.12438.0

Startup.cs

No need to add builder.Services.AddLogging(); it's imported automatically in the container.

using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;

[assembly: FunctionsStartup(typeof(MyFunctionsNamespace.Startup))]

namespace MyFunctionsNamespace
{
    public class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder)
        {
            builder.Services.AddTransient<IMyService, MyService>();
        }
    }
}

MyFunkyFunction.cs

using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Extensions.Logging;

namespace MyFunctionsNamespace
{
    public class MyFunkyFunction
    {
        private readonly IMyService _myService;

        public MyFunkyFunction(IMyService myService)
        {
            _myService = myService;
        }

        [FunctionName("FunkyFunc")]
        public async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]
            HttpRequest req
            , ILogger log
        )
        {
            log.LogInformation("C# HTTP trigger function processed a request.");

            _myService.Do();

            return new OkObjectResult("Hello");
        }
    }
}

IMyService.cs

Anything in LogCategories.CreateFunctionUserCategory will do the job. It seems to be some WebJob legacy requirement.

using Microsoft.Azure.WebJobs.Logging;
using Microsoft.Extensions.Logging;

namespace MyFunctionsNamespace
{
    public interface IMyService
    {
        void Do();
    }


    public class MyService : IMyService
    {
        private readonly ILogger _log;

        public MyService(ILoggerFactory loggerFactory)
        {
            // Important: Call CreateFunctionUserCategory, otherwise log entries might be filtered out
            // I guess it comes from Microsoft.Azure.WebJobs.Logging
            _log = loggerFactory.CreateLogger(LogCategories.CreateFunctionUserCategory("Common"));
        }

        public void Do()
        {
            _log.Log(LogLevel.Information, "Hello from MyService");
        }
    }
}
like image 24
Milen Stefanov Avatar answered Oct 19 '22 23:10

Milen Stefanov