IHttpClientFactory в ASP.NET Core типизированных клиентов - PullRequest
1 голос
/ 11 мая 2019

Я получаю сообщение об ошибке при попытке использовать типизированный клиент для HttpClient, как описано здесь: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-2.2

Вот мои настройки:

Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

    services.AddDefaultAWSOptions(Configuration.GetAWSOptions());

    services.AddHttpClient<IPStackService>(c =>
    {
        c.BaseAddress = new Uri(Configuration["IPStackURL"]);
    });

    services.AddHttpContextAccessor();

    services.AddTransient<IIPStackService, IPStackService>();
}

Контроллер:

[Route("api/[controller]")]
    [ApiController]
    public class RenderController : ControllerBase
    {
        private IConfiguration _configuration;
        private readonly ILogger _logger;
        private IIPStackService _ipMetaDataService;

        public RenderController(IConfiguration configuration,
                                ILogger<RenderController> logger,
                                IIPStackService ipStackService)
        {
            _configuration = configuration;
            _ipStackService = ipStackService;
            _logger = logger;
        }

        [HttpGet]
        [ProducesResponseType(StatusCodes.Status200OK)]
        [Produces("text/plain")]
        public async Task<ActionResult> GetAsync(string hostId, string clientUtc)
        {
            var ip = Common.ResolveIPAddress(HttpContext);

            var ipMetaData = await _ipStackService.GetByIPAsync(ip, _configuration["AccessKey"]);

            // removed for clarity

            return allowed ? Ok(true) : Ok(null);
        }
    }

Служба:

public class IPStackService : IIPStackService
{
    private readonly ILogger _logger;
    private readonly HttpClient _httpClient;

    public IPStackService(ILogger<IPStackService> logger, HttpClient client)
    {
        _logger = logger;
        _httpClient = client;
    }

    public async Task<IPMetaDataModel> GetByIPAsync(string ip, string accessKey)
    {
        var ipMetaData = new IPMetaDataModel();

        var response = await _httpClient.GetAsync($"/{ip}?access_key={accessKey}");
        response.EnsureSuccessStatusCode();

        // removed for clarity

        return ipMetaData;
    }
}

Получена ошибка:

Произошло необработанное исключение при обработке запроса.InvalidOperationException: невозможно разрешить службу для типа «System.Net.Http.HttpClient» при попытке активировать «WebScreen.Gate.Services.IPStackService».Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites (Тип serviceType, Тип instanceType типа, CallSiteChain callSiteChain, параметры ParameterInfo [], bool throwIfCallSiteNotFound)

* 1020, как правильно настроить*

1 Ответ

6 голосов
/ 11 мая 2019

Активатор для IPStackService (отражение кода) не может найти HttpClient в коллекции DI, поэтому вы получили исключение (специально для services.AddTransient<IIPStackService, IPStackService>()).

Кстати, вы добавилиуслуга IPStackService дважды в вашей коллекции DI:

  1. services.AddHttpClient<IPStackService>(...);.
  2. services.AddTransient<IIPStackService, IPStackService>();

Вам нужен только один, и так какесли вы используете типизированный клиент, вы можете решить свою проблему, удалив вторую и оставив первую, и чуть-чуть изменив первую, добавив контракт к реализации следующим образом:

services.AddHttpClient<IIPStackService, IPStackService>(c =>
{
     c.BaseAddress = new Uri(Configuration["IPStackURL"]);
});

The AddHttpClient позаботится о привязке HttpClinet к вашему сервису.


И если вы хотите использовать services.AddTransient<IIPStackService, IPStackService>(); вместо services.AddHttpClient, то вам нужно добавить HttpClinet кВаша коллекция DI как:

services.AddTransient<HttpClient>();
...