Как лучше всего настроить httpClients в ASP Net Core 3.0 во время запуска?

ASP NET Core 2.1 предоставил нам HttpClientFactory, который является отличным способом создания настраиваемых httpClients.

Мы использовали этот метод вместе со службой конфигурации конечной точки, которая была внедрена в конструктор класса startup.cs.

Код выглядел примерно так:

        public Startup(IConfiguration configuration, IEndpointService endpointService)
        {
            Configuration = configuration;
            _endpointService = endpointService;
        }

        public void ConfigureServices(IServiceCollection services)
        {
           foreach(var endpoint in _endpointService)
           {
              services.AddHttpClient(endpoint.name, c => {
                 c.BaseAddress = endpoint.Address;
                 // plus other config as required
              });
           }
        }

IEndpointService был настроен до внедрения Startup с помощью следующего вызова.

    IWebHostBuilder webHostBuilder =
        WebHost.CreateDefaultBuilder(args)
            .ConfigureServices((webHostBuilderContext, services) => {
                services.AddSingleton<IEndpointService, EndpointService>();
            })
            .UseStartup<Startup>();

Это позволило нам считывать информацию из внешнего источника данных и настраивать несколько именованных httpClients с разной конфигурацией.

Эта функция была удалена в ASP NET Core 3.0.

См .: https://weblogs.thinktecture.com/pawel/2017/08/aspnet-core-beware-singleton-may-not-be-singleton.html и https://andrewlock.net/avoiding-startup-service-jection-in-asp-net-core-3/

Это оставляет нам вопрос, как лучше всего достичь той же функциональности в версии 3.0.

Это лучшее, что я придумал до сих пор, но я очень хочу знать, каковы рекомендации по этому вопросу.

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton<IEndpointService, EndpointService>();

            using (var serviceProvider = services.BuildServiceProvider())
            {
                var endpointService = serviceProvider.GetService<IEndpointService>();

                foreach (var endpointConfiguration in endpointService.GetEndpointConfiguration())
                {
                    // Create a named client and any other configuration that we need to do here.
                    services.AddHttpClient(endpointConfiguration.Name, client =>
                    {
                        client.BaseAddress = endpointConfiguration.BaseAddress;

                        // Add any extra config that is required here
                    });
                }
            }
        }

В этом примере я принудительно создаю EndpointService с помощью serviceProvider.GetService.

Я осознаю тот факт, что я, вероятно, воссоздал ошибку с несколькими одиночками (см. Ссылки выше), но не уверен, что здесь лучший подход.

Мысли ?


person Phillip Steele    schedule 05.12.2019    source источник
comment
Проблема с одноэлементным HttpClient заключается в изменении записи DNS - см. https://byterot.blogspot.com/2016/07/singleton-httpclient-dns.html.   -  person stuartd    schedule 05.12.2019
comment
Вы совершенно правы, отсюда и причина использования HttpClientFactory. В приведенном выше сценарии я упоминаю, что можно иметь несколько одиночных экземпляров EndpointService. Ссылки описывают проблему более подробно.   -  person Phillip Steele    schedule 05.12.2019
comment
Я должен разобраться в этом, спасибо.   -  person stuartd    schedule 05.12.2019


Ответы (1)


Если EndpointService не имеет зависимостей, просто создайте экземпляр при построении хоста и используйте его в ConfigureServices удобном методе на построителе хоста.

IEndpointService endpointService = new EndpointService();
IWebHostBuilder webHostBuilder =
    WebHost.CreateDefaultBuilder(args)
        .ConfigureServices((webHostBuilderContext, services) => {
            foreach(var endpoint in endpointService.GetEndpointConfiguration()) {
                services.AddHttpClient(endpoint.name, c => {
                    c.BaseAddress = endpoint.Address;
                    // plus other config as required
                });
            }
        })
        .UseStartup<Startup>();//<--if this is still actually needed.
person Nkosi    schedule 05.12.2019
comment
К сожалению, это так, я не учел их для ясности. Тем не менее, спасибо за ваш ответ. Это стоит сделать в описанном вами сценарии. - person Phillip Steele; 05.12.2019
comment
@PhillipSteele, можете ли вы их включить, возможно, вы могли бы просто создать отдельную коллекцию сервисов для их решения. - person Nkosi; 05.12.2019