diff --git a/global.json b/global.json index ff8d898e..616b2c4e 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@  { "projects": [ "src", "test" ], "sdk": { - "version": "1.0.0-preview2-003133" + "version": "1.0.0-preview2-003131" } } diff --git a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs index 04ca1037..dbb98810 100644 --- a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs @@ -135,7 +135,7 @@ namespace Ocelot.DependencyInjection services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); // see this for why we register this as singleton http://stackoverflow.com/questions/37371264/invalidoperationexception-unable-to-resolve-service-for-type-microsoft-aspnetc // could maybe use a scoped data repository diff --git a/src/Ocelot/Requester/HttpClientBuilder.cs b/src/Ocelot/Requester/HttpClientBuilder.cs index 8cad9d49..d7939df0 100644 --- a/src/Ocelot/Requester/HttpClientBuilder.cs +++ b/src/Ocelot/Requester/HttpClientBuilder.cs @@ -11,61 +11,23 @@ namespace Ocelot.Requester { internal class HttpClientBuilder : IHttpClientBuilder { - private TimeSpan? _timeout; - private readonly List _handlers = new List(); + private readonly Dictionary> _handlers = new Dictionary>(); private Dictionary _defaultHeaders; - private CookieContainer _cookieContainer; - private IQoSProvider _qoSProvider; - public IHttpClientBuilder WithCookieContainer(CookieContainer cookieContainer) + public IHttpClientBuilder WithQos(IQoSProvider qosProvider, IOcelotLogger logger) { - _cookieContainer = cookieContainer; + _handlers.Add(5000, () => new PollyCircuitBreakingDelegatingHandler(qosProvider, logger)); return this; - } - public IHttpClientBuilder WithTimeout(TimeSpan timeout) - { - _timeout = timeout; - return this; - } - - public IHttpClientBuilder WithHandler(DelegatingHandler handler) - { - _handlers.Add(handler); - return this; - } - - public IHttpClientBuilder WithDefaultRequestHeaders(Dictionary headers) - { - _defaultHeaders = headers; - return this; - } + } public IHttpClient Create() { - HttpClientHandler httpclientHandler = null; - if (_cookieContainer != null) - { - httpclientHandler = new HttpClientHandler() { CookieContainer = _cookieContainer }; - } - else - { - httpclientHandler = new HttpClientHandler(); - } - - if (httpclientHandler.SupportsAutomaticDecompression) - { - httpclientHandler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; - } - + var httpclientHandler = new HttpClientHandler(); + var client = new HttpClient(CreateHttpMessageHandler(httpclientHandler)); - - if (_timeout.HasValue) - { - client.Timeout = _timeout.Value; - } - + if (_defaultHeaders == null) { return new HttpClientWrapper(client); @@ -81,11 +43,18 @@ namespace Ocelot.Requester private HttpMessageHandler CreateHttpMessageHandler(HttpMessageHandler httpMessageHandler) { - foreach (var handler in _handlers) - { - handler.InnerHandler = httpMessageHandler; - httpMessageHandler = handler; - } + + _handlers + .OrderByDescending(handler => handler.Key) + .Select(handler => handler.Value) + .Reverse() + .ToList() + .ForEach(handler => + { + var delegatingHandler = handler(); + delegatingHandler.InnerHandler = httpMessageHandler; + httpMessageHandler = delegatingHandler; + }); return httpMessageHandler; } } diff --git a/src/Ocelot/Requester/HttpClientHttpRequester.cs b/src/Ocelot/Requester/HttpClientHttpRequester.cs index f0566fed..06185b75 100644 --- a/src/Ocelot/Requester/HttpClientHttpRequester.cs +++ b/src/Ocelot/Requester/HttpClientHttpRequester.cs @@ -11,10 +11,10 @@ namespace Ocelot.Requester { public class HttpClientHttpRequester : IHttpRequester { - private IHttpClientMessageCacheHandler _cacheHandlers; + private readonly IHttpClientCache _cacheHandlers; private readonly IOcelotLogger _logger; - public HttpClientHttpRequester(IOcelotLoggerFactory loggerFactory, IHttpClientMessageCacheHandler cacheHandlers) + public HttpClientHttpRequester(IOcelotLoggerFactory loggerFactory, IHttpClientCache cacheHandlers) { _logger = loggerFactory.CreateLogger(); _cacheHandlers = cacheHandlers; @@ -24,23 +24,15 @@ namespace Ocelot.Requester { var builder = new HttpClientBuilder(); - builder.WithCookieContainer(request.CookieContainer); + var cacheKey = GetCacheKey(request, builder); - string baseUrl = $"{request.HttpRequestMessage.RequestUri.Scheme}://{request.HttpRequestMessage.RequestUri.Authority}"; - - if (request.IsQos) - { - builder.WithHandler(new PollyCircuitBreakingDelegatingHandler(request.QosProvider, _logger)); - baseUrl = $"{baseUrl}{request.QosProvider.CircuitBreaker.CircuitBreakerPolicy.PolicyKey}"; - } - - IHttpClient httpClient = _cacheHandlers.Get(baseUrl); + var httpClient = _cacheHandlers.Get(cacheKey); if (httpClient == null) { httpClient = builder.Create(); - _cacheHandlers.Set(baseUrl, httpClient, TimeSpan.FromMinutes(30)); - } - + _cacheHandlers.Set(cacheKey, httpClient, TimeSpan.FromHours(6)); + } + try { var response = await httpClient.SendAsync(request.HttpRequestMessage); @@ -62,5 +54,18 @@ namespace Ocelot.Requester } } + + private string GetCacheKey(Request.Request request, HttpClientBuilder builder) + { + string baseUrl = $"{request.HttpRequestMessage.RequestUri.Scheme}://{request.HttpRequestMessage.RequestUri.Authority}"; + + if (request.IsQos) + { + builder.WithQos(request.QosProvider, _logger); + baseUrl = $"{baseUrl}{request.QosProvider.CircuitBreaker.CircuitBreakerPolicy.PolicyKey}"; + } + + return baseUrl; + } } } \ No newline at end of file diff --git a/src/Ocelot/Requester/IHttpClientBuilder.cs b/src/Ocelot/Requester/IHttpClientBuilder.cs index 85fd5f69..832fd8d1 100644 --- a/src/Ocelot/Requester/IHttpClientBuilder.cs +++ b/src/Ocelot/Requester/IHttpClientBuilder.cs @@ -11,28 +11,11 @@ namespace Ocelot.Requester { public interface IHttpClientBuilder { - /// - /// Sets the cookie container used to store server cookies by the handler - /// - /// - /// - IHttpClientBuilder WithCookieContainer(CookieContainer cookieContainer); /// - /// Sets the number of milliseconds to wait before the request times out. + /// Sets a PollyCircuitBreakingDelegatingHandler . /// - IHttpClientBuilder WithTimeout(TimeSpan timeout); - - /// - /// Sets a DelegatingHandler. - /// Can be reused to set several different Handlers in a pipeline. - /// - IHttpClientBuilder WithHandler(DelegatingHandler handler); - - /// - /// Sets Default HttpRequestHeaders - /// - IHttpClientBuilder WithDefaultRequestHeaders(Dictionary headers); + IHttpClientBuilder WithQos(IQoSProvider qosProvider, IOcelotLogger logger); /// /// Creates the diff --git a/src/Ocelot/Requester/IHttpClientMessageCacheHandler.cs b/src/Ocelot/Requester/IHttpClientCache.cs similarity index 86% rename from src/Ocelot/Requester/IHttpClientMessageCacheHandler.cs rename to src/Ocelot/Requester/IHttpClientCache.cs index a2a93692..f4b8f76e 100644 --- a/src/Ocelot/Requester/IHttpClientMessageCacheHandler.cs +++ b/src/Ocelot/Requester/IHttpClientCache.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; namespace Ocelot.Requester { - public interface IHttpClientMessageCacheHandler + public interface IHttpClientCache { bool Exists(string id); IHttpClient Get(string id); diff --git a/src/Ocelot/Requester/MemoryHttpClientMessageCacheHandler.cs b/src/Ocelot/Requester/MemoryHttpClientCache.cs similarity index 70% rename from src/Ocelot/Requester/MemoryHttpClientMessageCacheHandler.cs rename to src/Ocelot/Requester/MemoryHttpClientCache.cs index bb948b8a..33ff15a1 100644 --- a/src/Ocelot/Requester/MemoryHttpClientMessageCacheHandler.cs +++ b/src/Ocelot/Requester/MemoryHttpClientCache.cs @@ -7,18 +7,18 @@ using System.Threading.Tasks; namespace Ocelot.Requester { - public class MemoryHttpClientMessageCacheHandler : IHttpClientMessageCacheHandler + public class MemoryHttpClientCache : IHttpClientCache { private readonly IMemoryCache _memoryCache; - public MemoryHttpClientMessageCacheHandler(IMemoryCache memoryCache) + public MemoryHttpClientCache(IMemoryCache memoryCache) { _memoryCache = memoryCache; } - public void Set(string id, IHttpClient counter, TimeSpan expirationTime) + public void Set(string id, IHttpClient client, TimeSpan expirationTime) { - _memoryCache.Set(id, counter, new MemoryCacheEntryOptions().SetAbsoluteExpiration(expirationTime)); + _memoryCache.Set(id, client, new MemoryCacheEntryOptions().SetAbsoluteExpiration(expirationTime)); } public bool Exists(string id)