Правильный способ регистрации сторонней платформы DI Framework (Lamar/Autofac) в функциях Azure V2
Функции Azure 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 на структуру DI "Lamar".
В их документации есть пример для 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. Единственным способом, которым я смог перехватить инициализацию лазурных функций, был либо FunctionsStartup, который настраивает IFunctionsHostBuilder, либо IWebJobsStartup, который настраивает IWebJobsBuilder, но я не нахожу расширений для таких сборок на 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>();
}
}
}
2 ответа
После некоторого исследования я смог найти решение с помощью Autofac. Я не смог сделать это с Lamar, у него не было расширения ни для IFunctionsHostBuilder, ни для IWebJobsBuilder.
Исходный код: расширения привязки для внедрения зависимостей в функции Azure v2
Nuget: https://www.nuget.org/packages/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.
Я создал новый способ использования Autofac DI в проекте Azure Functions v3 без использования статических функций или атрибутов вставки. Списание услуг вызывается с использованием соответствующей области.
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)
{
...
}