Вопрос о сроке службы внедрения зависимостей Azure Function V3

#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. Большое вам спасибо — это была проблема. Очень логично и кажется очевидным в ретроспективе, но я смотрел на это часами и не понимал этого. Спасибо!!