2

Azure Functions V2 现在支持.net 依赖注入

为了实现这一点,您需要执行以下代码:

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

namespace MyNamespace
{
    public class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder)
        {
            builder.Services.AddHttpClient();
            builder.Services.AddSingleton((s) => {
                return new CosmosClient(Environment.GetEnvironmentVariable("COSMOSDB_CONNECTIONSTRING"));
            });
            builder.Services.AddSingleton<ILoggerProvider, MyLoggerProvider>();
        }
    }
}

我想将默认容器从 .net 更改为“Lamar”DI 框架。

在他们的文档中,他们有一个 WebHost 的示例

var builder = new WebHostBuilder();
builder
    // Replaces the built in DI container
    // with Lamar
    .UseLamar()

    // Normal ASP.Net Core bootstrapping
    .UseUrls("http://localhost:5002")
    .UseKestrel()
    .UseStartup<Startup>();

builder.Start();

但我无法将 IFunctionsHostBuilder 更改为使用“UseLamar()”扩展名。因为这扩展了 IWebHostBuilder。我能够拦截天蓝色函数初始化的唯一方法是使用配置 IFunctionsHostBuilder 的FunctionsStartup或配置 IWebJobsBuilder 的IWebJobsStartup 但我在 Lamar 上找不到此类构建的扩展。

我试图检查现有的扩展来创建类似的代码,但没有工作,因为可能我需要创建更多的东西:

[assembly: FunctionsStartup(typeof(FunctionAppPrototype.Startup))]
namespace FunctionAppPrototype
{
    public class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder)
        {
            var container = new Container(x =>
            {
                x.AddTransient<IMyService, MyService>();
            });

            builder.Services.AddSingleton<IServiceProviderFactory<IServiceCollection>, LamarServiceProviderFactory>();
            builder.Services.AddSingleton<IServiceProviderFactory<ServiceRegistry>, LamarServiceProviderFactory>();
        }
    }
}
4

2 回答 2

3

经过一番研究,我能够找到使用 Autofac 的解决方案。我无法用 Lamar 做到这一点,它对于 IFunctionsHostBuilder 或 IWebJobsBuilder 都没有扩展。

源代码:Azure Function v2 中依赖注入的绑定扩展

Nuget:Willezone.Azure.WebJobs.Extensions.DependencyInjection

首先,您需要通过执行以下代码来拦截函数应用的启动:

[assembly: WebJobsStartup(typeof(AutoFacFunctionAppPrototype.WebJobsStartup))]

namespace AutoFacFunctionAppPrototype
{
    public class WebJobsStartup : IWebJobsStartup
    {
        public void Configure(IWebJobsBuilder builder) =>
            builder.AddDependencyInjection<AutoFacServiceProviderBuilder>();
    }
}

然后创建容器并注册依赖项:

namespace AutoFacFunctionAppPrototype.Builders
{
    public class AutoFacServiceProviderBuilder : IServiceProviderBuilder
    {
        private readonly IConfiguration configuration;

        public AutoFacServiceProviderBuilder(IConfiguration configuration) 
            => this.configuration = configuration;

        public IServiceProvider Build()
        {
            var services = new ServiceCollection();
            services.AddTransient<ITransientService, TransientService>();
            services.AddScoped<IScopedService, ScopedService>();

            var builder = new ContainerBuilder();

            builder.RegisterType<SingletonService>().As<ISingletonService>().SingleInstance();

            builder.Populate(services); // Populate is needed to have support for scopes.
            return new AutofacServiceProvider(builder.Build());
        }
    }
}

然后您可以使用属性 [Inject] 在函数上使用它们:

namespace AutoFacFunctionAppPrototype.Functions
{
    public static class CounterFunction
    {
        [FunctionName("Counter")]
        public static IActionResult Run(
            [HttpTrigger(AuthorizationLevel.Function, "get")] HttpRequest req,
            [Inject]ITransientService transientService,
            [Inject]IScopedService scopedService,
            [Inject]ISingletonService singletonService,
             ILogger logger)
        {
            logger.LogInformation("C# HTTP trigger function processed a request.");

            string result = String.Join(Environment.NewLine, new[] {
                $"Transient: {transientService.GetCounter()}",
                $"Scoped: {scopedService.GetCounter()}",
                $"Singleton: {singletonService.GetCounter()}",
            });
            return new OkObjectResult(result);
        }
    }
}

使用这种方法,我只能注入参数,不能进行构造函数或属性注入,即使我是一个非静态类。

注意:如果将来 Autofac 支持 IFunctionsHostBuilder 的扩展,可能会更好地使用该方法而不是 IWebJobsStartup。

于 2019-09-04T08:55:09.347 回答
2

我创建了一种在 Azure Functions v3 项目中使用 Autofac DI 的新方法,而无需使用静态函数或注入属性。使用适当的范围调用服务的处置。

GitHub:https
://github.com/junalmeida/autofac-azurefunctions NuGet:https ://www.nuget.org/packages/Autofac.Extensions.DependencyInjection.AzureFunctions

随时与我一起贡献!

例子

public class Function1 
{
    private readonly IService1 _service1;

    public Function1(IService1 service1)
    {
        _service1 = service1;
    }

    [FunctionName(nameof(Function1))]
    public async Task Run([QueueTrigger("myqueue-items", Connection = "AzureWebJobsStorage")]string myQueueItem, ILogger log)
    {
        ...
    }
于 2020-03-12T00:45:23.540 回答