【问题标题】:How can I use the new DI to inject an ILogger into an Azure Function using IWebJobsStartup?如何使用新的 DI 将 ILogger 注入使用 IWebJobsStartup 的 Azure 函数?
【发布时间】:2019-02-26 00:30:07
【问题描述】:

我正在使用Azure Function v2。这是我使用构造函数注入的函数:

public sealed class FindAccountFunction
{
    private readonly IAccountWorkflow m_accountWorkflow;

    private readonly IMapper m_mapper;

    private readonly ILogger m_logger;

    public FindAccountFunction(ILogger logger, IMapper mapper, IAccountWorkflow accountWorkflow)
    {
        m_logger = logger;
        m_mapper = mapper;
        m_accountWorkflow = accountWorkflow;
    }

    [FunctionName("FindAccount")]
    public async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, Verbs.Get, Route = "v1/accounts/")] HttpRequest httpRequest, ILogger logger)
    {
        // Do stuff.
    }
}

我在派生自 IWebJobsStartup 的 Startup 类中声明了我想要注入到 Azure 函数中的所有依赖项:

    public sealed class Startup : IWebJobsStartup
    {
        public void Configure(IWebJobsBuilder webJobsBuilder)
        {
            //  Registers the application settings' class.
            webJobsBuilder.Services.AddSingleton<IApplicationSettings, ApplicationSettings>();

            //  ** Registers the ILogger instance **
            //  ** ?? **

            //  Registers the IMapper instance for the contracts.
            var mapperConfiguration = new MapperConfiguration(cfg => cfg.AddProfile(new MyProfile()));

     webJobsBuilder.Services.AddSingleton(mapperConfiguration.CreateMapper());

            // Registers custom services.
            webJobsBuilder.Services.AddTransient<IStorageService, StorageService>();

            webJobsBuilder.Services.AddTransient<IAccountWorkflow, AccountWorkflow>();
        }
   }

Azure 函数调用其他也依赖 ILogger 的注入服务,例如 IAccountWorkflow

public sealed class AccountWorkflow : IAccountWorkflow
{  
    public AccountWorkflow(ILogger logger, IStorageService storageService)
    {
        if(logger is null)
            throw new ArgumentNullException();
    }
}

问题在于 DI 无法找到任何 ILogger 实现并且无法解析服务,因为注入了一个空的 ILogger

问题

如何在IWebJobsStartup 中设置ILogger 的注入?

【问题讨论】:

  • 我认为函数应该是静态的?
  • 天哪 :) 。我今天才发现这一点,这让我很开心。现在,我们可以删除 static 关键字并进行一些甜蜜的 ctor 注入。我只需要注入该死的记录器就可以让它变得完美:)
  • 哦,这是新的吗?有没有我可以研究的文档?
  • @Nkosi 这是在天蓝色函数中使用 DI 的工作的一部分。你可以看看这个问题:Dependency Injection support for Functions。见Port changes to enable instance methods
  • @Nkosi 因此,自运行时 v2.0.12265 起支持实例方法:Azure Functions Runtime 2.0.12265

标签: c# azure dependency-injection azure-functions


【解决方案1】:

更新

参考Use dependency injection in .NET Azure Functions

注册服务

要注册服务,您可以创建一个配置方法并将组件添加到IFunctionsHostBuilder 实例。 Azure Functions 主机创建一个IFunctionsHostBuilder 并将其直接传递到您配置的方法中。

要注册你的配置方法,你必须添加一个程序集属性 指定您的配置方法的类型,使用 FunctionsStartup 属性。

所以在这种情况下

[assembly: FunctionsStartup(typeof(MyNamespace.Startup))]    
namespace MyNamespace {
    public class Startup : FunctionsStartup {
        public override void Configure(IFunctionsHostBuilder builder) {
            //  ** Registers the ILogger instance **
            builder.Services.AddLogging();

            //  Registers the application settings' class.
            //...

            //...omitted for brevity    
        }
    }
}

原创

我相信既然您可以访问服务集合,您应该可以向它添加日志记录

public void Configure(IWebJobsBuilder webJobsBuilder) {       

    //  ** Registers the ILogger instance **
    webJobsBuilder.Services.AddLogging();

    //OR
    //webJobsBuilder.Services.AddLogging(builder => {
    //    //...
    //});

    //  Registers the application settings' class.
    //...

    //...removed for brevity
}

并且在函数的构造函数中有一个ILoggerFactory

//...

//Ctor
public FindAccountFunction(ILoggerFactory loggerFactory, IMapper mapper, IAccountWorkflow accountWorkflow) {
    m_logger = loggerFactory.CreateLogger<FindAccountFunction>();
    m_mapper = mapper;
    m_accountWorkflow = accountWorkflow;
}

//...

【讨论】:

  • 我觉得这有点过时了,应该改用FunctionsStartup
  • @Kapé 是正确的。这将在该版本发布之前完成。感谢您提供参考链接。我已更新答案以反映最新版本。
  • 感谢更新,但我认为 builder.Services.AddLogging(); 也不再需要了?似乎已经在Services 集合中设置了。
  • 使用ILogger&lt;Name of constructor's class&gt; 效果很好。
  • @user3613932 是的,较新的版本默认添加了日志记录,因此使用ILogger&lt;T&gt; 应该是开箱即用的。
【解决方案2】:

我设法解决了这个问题:

如下注入我的班级:

MyClass.cs:

public class MyClass
{
    private readonly ILogger<MyClass> _logger;

    public MyClass(ILogger<MyClass> logger)
    {
        _logger = logger;
    }
}

Startup.cs:

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

namespace Namespace {    
public class Startup : FunctionsStartup 
{
    public override void Configure(IFunctionsHostBuilder builder) 
    {
        builder.Services.AddLogging(); 
    }
  }
}

【讨论】:

  • 它对我有用。但是,重要的是像 ILogger&lt;MyClass&gt; _logger 而不是 ILogger _logger 那样注入它
【解决方案3】:

您应该从您的启动类中删除对AddLogging 方法的调用。默认记录器已由 azure 函数主机设置。

[assembly: WebJobsStartup(typeof(StartUp))]
public class StartUp : IWebJobsStartup
{
    public void Configure(IWebJobsBuilder builder)
    {
        builder.Services.AddSingleton<AppSettings>();

        builder.Services.AddTransient<IMyService, MyService>();
    }
}

public MyFunction(IMyService service, ILogger<IMyService> logger)
{
    this.service = service;
    this.logger = logger;
}

Azure Functions Runtime 2.0.12265 起,Azure 函数现在支持实例方法

【讨论】:

  • 哼...还是同样的错误。我必须使用 ILogger 的通用版本吗?
  • 是的,它只适用于昨天的通用版本 :)
  • 我认为只有 ILogger 注册了services.AddLogging()。见LoggingServiceCollectionExtensions
  • 我没有任何错误,但我没有看到以前的日志(在 Azure 函数监视器部分或 App Insights 中)...需要更多调查以确保它确实有效
  • @Kzrystof 添加到host.json 以下代码"logging": { "logLevel": { "default": "Information" } }
【解决方案4】:

除了在函数 Startup 类中注册类之外,我们还需要在 host.json 文件中添加命名空间,以便将消息记录到 App 洞察力。如果我们不添加它,它只会将消息记录到本地控制台,但在 azure 上部署时,它不会记录任何内容,也不会给出任何错误。

{
  "version": "2.0",
  "logging": {
    "logLevel": {
      "FunctionProjectNameSpace.RegisteredClass": "Information"
    }
  }
}

此处的示例代码供参考 - https://gist.github.com/nareshnagpal06/82c6b4df2a987087425c32adb58312c2

【讨论】:

    【解决方案5】:

    你可以添加

      "logging": {
        "fileLoggingMode": "debugOnly",
        "logLevel": {
          "default": "Information"
        }
      }
    

    如果要使用IloggerFactory,无需添加DI

    【讨论】:

    • 我已经测试了这里列出的所有方法,而且这种方法最省力 - 只需确保将 ILogger&lt;T&gt; 输入到函数的 ctor 中。
    猜你喜欢
    • 2019-03-05
    • 2020-03-08
    • 2020-12-03
    • 1970-01-01
    • 1970-01-01
    • 2019-05-21
    • 1970-01-01
    • 2019-07-29
    • 2020-12-10
    相关资源
    最近更新 更多