#dependency-injection #azure-functions #azure-function-app
#внедрение зависимостей #azure-функции #azure-function-app
Вопрос:
Я использую функции Azure v3 и DI. У меня есть служба, которую я настраиваю с временным сроком службы в моем StartUp.cs (используя: builder.Services.AddTransient<ICoreApiClient>(s => coreApiService);
), а затем я внедряю в свой класс функций Azure. Функция Azure — это функция запуска очереди хранения.
Я ожидаю, что для каждого сообщения очереди я получу отдельный экземпляр моего «coreApiService», но, похоже, я делюсь одним экземпляром, когда несколько сообщений помещаются в очередь одновременно.
Неверно ли мое ожидание получения отдельного экземпляра для каждого вызова или «запуска»? Проблема, с которой я сталкиваюсь, заключается в том, что «_coreApiClient», по-видимому, используется совместно несколькими вызовами метода Run, так как я устанавливаю в нем свойства (например, «Идентификатор клиента» или «Ключ API» и т.д.), Которые действительны для одного сообщения и должны оставаться для его обработкисообщение изменяется по мере начала обработки следующего сообщения.
Я делаю это неправильно или неправильно понимаю время жизни?
Вот мой стартовый код:
public class Startup: FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddLogging();
var loggingService = new HttpLoggingService(Environment.GetEnvironmentVariable("LoggingURL"), 0, "ABC.Integrations");
builder.Services.AddTransient<ILoggingService>(s => loggingService);
int CoreApiTimeout = 60; //Environment.GetEnvironmentVariable("CoreApiTimeout")
var coreApiService = new CoreApiClient(Environment.GetEnvironmentVariable("CoreApiKey"),string.Empty, CoreApiTimeout,Environment.GetEnvironmentVariable("CoreApiBaseUrl"));
builder.Services.AddTransient<ICoreApiClient>(s => coreApiService);
}
}
И мой класс функций Azure:
public class TaskRouter
{
private readonly ICoreApiClient _coreApiClient;
private readonly ILoggingService _upgLogger;
private readonly ILogger<TaskRouter> _log;
public TaskRouter(ICoreApiClient coreApiClient, ILoggingService upgLogger, ILogger<TaskRouter> log)
{
_coreApiClient = coreApiClient;
_upgLogger = upgLogger;
_log = log;
}
[FunctionName("RouteTask")]
[ExponentialBackoffRetry(5, "00:00:04", "00:03:00")]
public async Task Run([QueueTrigger("task-scheduler", Connection = "")]
string queueItem)
{
//Call Appropriate Function to start task
var taskMsg = JsonConvert.DeserializeObject<TaskMessage>(queueItem);
_coreApiClient.SetId(taskMsg.TaskNumber);
//DO SOME WORK HERE
Console.Log(_coreApiClient.GetId); //Will be different b/c this was set by the next message
}
}
Ответ №1:
Хотя клиент зарегистрирован в контейнере как переходный, на самом деле он является одноэлементным, поскольку экземпляр, созданный при запуске, является единственным экземпляром, который когда-либо будет возвращен для каждого вызова для внедрения ICoreApiClient
.
Переместите создание экземпляра в делегат фабрики, сделав это фактической временной регистрацией, так что каждый раз, когда новый экземпляр будет инициализироваться ICoreApiClient
, необходимо разрешить у поставщика услуг.
//...
builder.Services.AddTransient<ICoreApiClient>(s =>
new CoreApiClient(Environment.GetEnvironmentVariable("CoreApiKey"), string.Empty, CoreApiTimeout, Environment.GetEnvironmentVariable("CoreApiBaseUrl"))
);
//...
Комментарии:
1. Большое вам спасибо — это была проблема. Очень логично и кажется очевидным в ретроспективе, но я смотрел на это часами и не понимал этого. Спасибо!!