public async Task<List<Message>> GetMessagesAsync()
{
var uri = "http://www.contoso.com/messages";
       using (HttpClient client = new HttpClient())
        {
       		HttpResponseMessage response = await client.GetAsync(uri);
                response.EnsureSuccessStatusCode();
                return await response.Content.ReadAsAsync<List<Message>>();
        }
}

public class MessagesServices
{
private HttpClientHandler _httpClientHandler;

        public MessagesServices()
        {
        		_httpClientHandler = new HttpClientHandler();
        }

        public async Task<Message> GetMessagesAsync(int id)
        {
         	var uri = $"http://www.contoso.com/message/{id}";
        		using (var client = new HttpClient(_httpClientHandler, false))
                using (var response = await client.GetAsync(uri))
{
                		response.EnsureSuccessStatusCode();
                		return await response.Content.ReadAsAsync<Message>();
}
        }

        public async Task<List<Message>> GetMessagesAsync()
        {
                var uri = "http://www.contoso.com/messages";
                using (var client = new HttpClient(_httpClientHandler, false))
                using (var response = await client.GetAsync(uri))
{
                		response.EnsureSuccessStatusCode();
                		return await response.Content.ReadAsAsync<List<Message>>();
}	
        }
}

public class MessagesServices
{
private IHttpClientFactory _httpClientFactory;

        public MessagesServices(IHttpClientFactory httpClientFactory)
        {
        		_httpClientFactory = httpClientFactory;
        }

        public async Task<Message> GetMessagesAsync(int id)
        {
         	var uri = $"http://www.contoso.com/message/{id}";
        		using (var client = _httpClientFactory.CreateClient())
                using (var response = await client.GetAsync(uri))
{
                		response.EnsureSuccessStatusCode();
                		return await response.Content.ReadAsAsync<Message>();
}
        }

        public async Task<List<Message>> GetMessagesAsync()
        {
                var uri = "http://www.contoso.com/messages";
                using (var client = _httpClientFactory.CreateClient())
                using (var response = await client.GetAsync(uri))
{
                		response.EnsureSuccessStatusCode();
                		return await response.Content.ReadAsAsync<List<Message>>();
}	
        }
}

public class MessagesServices : IMessagesServices
{
private HttpClient _client;
        public MessagesServices(HttpClient client)
        {
        		_client = client;
        }

        public async Task<Message> GetMessagesAsync(int id)
        {
         	var uri = $"/message/{id}";
                using (var response = await _client.GetAsync(uri))
{
                		response.EnsureSuccessStatusCode();
                		return await response.Content.ReadAsAsync<Message>();
}
        }

        public async Task<List<Message>> GetMessagesAsync()
        {
                var uri = "/messages";
                using (var response = await _client.GetAsync(uri))
{
                		response.EnsureSuccessStatusCode();
                		return await response.Content.ReadAsAsync<List<Message>>();
}	
        }
}

public interface ICircuitBreakerPolicyConfig
{
       int RetryCount { get; set; }
       int BreakDuration { get; set; }
}
public interface IRetryPolicyConfig
{
       int RetryCount { get; set; }
}
public class PolicyConfig : ICircuitBreakerPolicyConfig, IRetryPolicyConfig
{
       public int RetryCount { get; set; }
       public int BreakDuration { get; set; }
}

public static class HttpRetryPolicies
    {
        public static RetryPolicy<HttpResponseMessage> GetHttpRetryPolicy(ILogger logger, IRetryPolicyConfig retryPolicyConfig)
        {
            return HttpPolicyBuilders.GetDefaultBuilder()
                                          .WaitAndRetryAsync(retryPolicyConfig.RetryCount,
                                                             ComputeDuration,
                                                             (result, timeSpan, retryCount, context) =>
                                                             {
                                                                 OnHttpRetry(result, timeSpan, retryCount, context, logger);
                                                             });
        }

        private static void OnHttpRetry(DelegateResult<HttpResponseMessage> result, TimeSpan timeSpan, int retryCount, Polly.Context context, ILogger logger)
        {
            if (result.Result != null)
            {
                logger.LogWarning("Request failed with {StatusCode}. Waiting {timeSpan} before next retry. Retry attempt {retryCount}", result.Result.StatusCode, timeSpan, retryCount);
            }
            else
            {
                logger.LogWarning("Request failed because network failure. Waiting {timeSpan} before next retry. Retry attempt {retryCount}", timeSpan, retryCount);
            }
        }

        private static TimeSpan ComputeDuration(int input)
        {
            return TimeSpan.FromSeconds(Math.Pow(2, input)) + TimeSpan.FromMilliseconds(new Random().Next(0, 100));
        }
    }

public class HttpCircuitBreakerPolicies
    {
        public static CircuitBreakerPolicy<HttpResponseMessage> GetHttpCircuitBreakerPolicy(ILogger logger, ICircuitBreakerPolicyConfig circuitBreakerPolicyConfig)
        {
            return HttpPolicyBuilders.GetDefaultBuilder()
                                          .CircuitBreakerAsync(circuitBreakerPolicyConfig.RetryCount + 1,
                                                               TimeSpan.FromSeconds(circuitBreakerPolicyConfig.BreakDuration),
                                                               (result, breakDuration) =>
                                                               {
                                                                   OnHttpBreak(result, breakDuration, circuitBreakerPolicyConfig.RetryCount, logger);
                                                               },
                                                               () =>
                                                               {
                                                                   OnHttpReset(logger);
                                                               });
        }

        public static void OnHttpBreak(DelegateResult<HttpResponseMessage> result, TimeSpan breakDuration, int retryCount, ILogger logger)
        {
            logger.LogWarning("Service shutdown during {breakDuration} after {DefaultRetryCount} failed retries.", breakDuration, retryCount);
            throw new BrokenCircuitException("Service inoperative. Please try again later");
        }

        public static void OnHttpReset(ILogger logger)
        {
            logger.LogInformation("Service restarted.");
        }
    }

public static class HttpClientBuilderExtensions
    {
        public static IHttpClientBuilder AddPolicyHandlers(this IHttpClientBuilder httpClientBuilder, string policySectionName, ILoggerFactory loggerFactory, IConfiguration configuration)
        {
            var retryLogger = loggerFactory.CreateLogger("PollyHttpRetryPoliciesLogger");
            var circuitBreakerLogger = loggerFactory.CreateLogger("PollyHttpCircuitBreakerPoliciesLogger");

            var policyConfig = new PolicyConfig();
            configuration.Bind(policySectionName, policyConfig);

            var circuitBreakerPolicyConfig = (ICircuitBreakerPolicyConfig)policyConfig;
            var retryPolicyConfig = (IRetryPolicyConfig)policyConfig;

            return httpClientBuilder.AddRetryPolicyHandler(retryLogger, retryPolicyConfig)
                                    .AddCircuitBreakerHandler(circuitBreakerLogger, circuitBreakerPolicyConfig);
        }

        public static IHttpClientBuilder AddRetryPolicyHandler(this IHttpClientBuilder httpClientBuilder, ILogger logger, IRetryPolicyConfig retryPolicyConfig)
        {
            return httpClientBuilder.AddPolicyHandler(HttpRetryPolicies.GetHttpRetryPolicy(logger, retryPolicyConfig));
        }

        public static IHttpClientBuilder AddCircuitBreakerHandler(this IHttpClientBuilder httpClientBuilder, ILogger logger, ICircuitBreakerPolicyConfig circuitBreakerPolicyConfig)
        {
            return httpClientBuilder.AddPolicyHandler(HttpCircuitBreakerPolicies.GetHttpCircuitBreakerPolicy(logger, circuitBreakerPolicyConfig));
        }
    }

public class Startup
{
    public Startup(IConfiguration configuration, ILoggerFactory loggerFactory)
    {
        Configuration = configuration;
        LoggerFactory = loggerFactory;
    }

    public IConfiguration Configuration { get; }

    public ILoggerFactory LoggerFactory { get; }

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

        public void ConfigureServices(IServiceCollection services)
    	{
	services.AddHttpClient<IMessagesServices, MessagesServices>(client =>
        		{
        			client.BaseAddress = new Uri("http://www.contoso.com");
        		}).AddPolicyHandlers("PolicyConfig", LoggerFactory, Configuration);
	}
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        app.UseMvc();
    }
}