Skip to content

Integration Test: WebApplicationFactory cannot create custom HttpClient that is registered via IServiceCollection.AddHttpClient<T> #5967

Closed
@PingPongSet

Description

@PingPongSet

I register HttpClient via IServiceCollection.AddHttpClient<T>(). However, it seems there is no way to create an HttpClient for T. Because WebApplicationFactory has only CreateClient(); method.

public void ConfigureServices(IServiceCollection services)
{
...
   services.SetWaitAndRetryPolicy<CustomHttpClient>();
}

 public static class IServiceCollectionExtension
    {
        public static void SetWaitAndRetryPolicy<T>(this IServiceCollection services) where T : class
        {
//https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-requests
            //https://github.com/App-vNext/Polly/wiki/Polly-and-HttpClientFactory            
            Random random = new Random();
            Config config = null;
            services.AddHttpClient<T>((sp, client) => 
                            config = sp.GetService<IOptions<Config>>().Value)                               
                   .AddPolicyHandler((service, request) =>

                        //TransientErrors:
                        //Network failures(System.Net.Http.HttpRequestException)
                        //HTTP 5XX status codes(server errors)
                        //HTTP 408 status code(request timeout)
                        HttpPolicyExtensions.HandleTransientHttpError()

                            //Wait and retry with exponential backoff with Randomisation
                            .WaitAndRetryAsync(config.Retry.RetryCount,
                                retryCount => TimeSpan.FromSeconds(Math.Pow(2, retryCount)) + //2,4,8,...
                                              TimeSpan.FromMilliseconds(random.Next(100, 990)), //random in millisecs
                                onRetry: (outcome, timespan, retryCount, context) =>
                                {
                                    service.GetService<ILog>().Info("Delaying for {delay}ms, then making retry {retry}.",
                                        timespan.TotalMilliseconds, retryCount);
                                }
                            )
                    )
                    .AddPolicyHandler((service, request) =>                      
                            HttpPolicyExtensions.HandleTransientHttpError()
                                //Further external requests are blocked for 30 seconds if five failed attempts occur sequentially.
                                //Circuit breaker policies are stateful.All calls through this client share the same circuit state.
                                .CircuitBreakerAsync(config.CircuitBreaker.HandledEventsAllowedBeforeBreaking,
                                             TimeSpan.FromSeconds(config.CircuitBreaker.DurationOfBreakInSeconds), 
                                             (result, timeSpan, context)=>
                                                    service.GetService<ILog>().Info("CircuitBreaker onBreak for {delay}ms", timeSpan.TotalMilliseconds),
                                              context =>
                                                    service.GetService<ILog>().Info("CircuitBreaker onReset")));


        }
    }

public class HttpClientService
    {
        private readonly HttpClient _client;
        private readonly ILog _logger;

        public HttpClientService(HttpClient client, ILog logger)
        {
            _client = client;
            _logger = logger;
        }

        public async Task<HttpStatusCode> PostAsync(string url, Dictionary<string, string> headers, string body)
        {
            using (var content = new StringContent(body, Encoding.UTF8, "application/json"))
            {
                foreach (var keyValue in headers)
                {
                    content.Headers.Add(keyValue.Key, keyValue.Value);
                }
                var response = await _client.PostAsync(url, content);              
                response.EnsureSuccessStatusCode();
                return response.StatusCode;
            }

        }
    }

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-mvcIncludes: MVC, Actions and Controllers, Localization, CORS, most templatesquestion

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions