dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.43k stars 10.01k forks source link

Typed HttpClient is not getting configuration from service registration #29816

Closed AlexeyShok closed 3 years ago

AlexeyShok commented 3 years ago

Describe the bug

I register a typed HttpClient with Startup and give it settings (BaseAddress and DefaultRequestHeaders). But these settings don't go to the HttpClient instance in the service. Instead, an HttpClient instance is instantiated with default settings.

To Reproduce

In Startup.cs ` public void ConfigureServices(IServiceCollection services) { var avazaBaseUrl = Configuration["Avaza:BaseUrl"]; var avazaAccessToken = Configuration["Avaza:PersonalAccessToken"]; services.AddHttpClient<IAvazaService, AvazaService>(client => { client.BaseAddress = new Uri(avazaBaseUrl); client.DefaultRequestHeaders.Add("Accept", "application/json"); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", avazaAccessToken); });

        services.AddServices();
        services.AddControllers();
        services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc("v1", new OpenApiInfo { Title = "WebApi", Version = "v1" });
        });
    }`

AvazaService.cs ` public class AvazaService : IAvazaService { private readonly HttpClient _httpClient;

    public AvazaService(HttpClient httpClient)
    {
        _httpClient = httpClient; // BaseAddress is null, DefaultRequestHeaders is empty
    }

    public async Task<Result<List<Timesheet>>> GetTimesheets()
    {
        var response = await _httpClient.GetAsync("api/Timesheet");

        if (!response.IsSuccessStatusCode)
            return Result.Failure<List<Timesheet>>($"Avaza returns: '{(int)response.StatusCode} {response.ReasonPhrase}' on request in GetTimesheets method");

        using var responseStream = await response.Content.ReadAsStreamAsync();
        var timesheetList = await JsonSerializer.DeserializeAsync<TimesheetList>(responseStream);

        return timesheetList.Timesheets;
    }
}`

Exceptions (if any)

System.InvalidOperationException: An invalid request URI was provided. The request URI must either be an absolute URI or BaseAddress must be set. at System.Net.Http.HttpClient.PrepareRequestMessage(HttpRequestMessage request) at System.Net.Http.HttpClient.CheckRequestBeforeSend(HttpRequestMessage request) at System.Net.Http.HttpClient.SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken) at System.Net.Http.HttpClient.GetAsync(String requestUri) at WebApi.Services.AvazaService.GetTimesheets(Timesheet timesheetRequest) in C:\Users\Alexe\source\repos\HorizonOne\AvazaConnector\WebApi\Services\AvazaService.cs:line 26 at WebApi.Services.MainService.LoadTimesheets() in C:\Users\Alexe\source\repos\HorizonOne\AvazaConnector\WebApi\Services\MainService.cs:line 26 at WebApi.Controllers.MainController.LoadTimesheets() in C:\Users\Alexe\source\repos\HorizonOne\AvazaConnector\WebApi\Controllers\MainController.cs:line 34 at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.gAwaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync() --- End of stack trace from previous location --- at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.gAwaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope) at Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext) at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

Further technical details

Среда выполнения: OS Name: Windows OS Version: 10.0.19042 OS Platform: Windows RID: win10-x64 Base Path: C:\Program Files\dotnet\sdk\5.0.101\

Host (useful for support): Version: 5.0.1 Commit: b02e13abab

.NET SDKs installed: 5.0.101 [C:\Program Files\dotnet\sdk]

.NET runtimes installed: Microsoft.AspNetCore.All 2.1.23 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All] Microsoft.AspNetCore.App 2.1.23 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 3.1.10 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 5.0.1 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.NETCore.App 2.1.23 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 3.1.10 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 5.0.1 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.WindowsDesktop.App 3.1.10 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App] Microsoft.WindowsDesktop.App 5.0.1 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

To install additional .NET runtimes or SDKs: https://aka.ms/dotnet-download

AlexeyShok commented 3 years ago

I registered the service twice, re-registration overlapped the HttpClient settings