mirror of
				https://github.com/nsnail/Ocelot.git
				synced 2025-11-04 13:50:49 +08:00 
			
		
		
		
	@@ -1,5 +1,4 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Cache
 | 
			
		||||
{
 | 
			
		||||
@@ -9,5 +8,25 @@ namespace Ocelot.Cache
 | 
			
		||||
        void AddAndDelete(string key, T value, TimeSpan ttl, string region);
 | 
			
		||||
        T Get(string key, string region);
 | 
			
		||||
        void ClearRegion(string region);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class NoCache<T> : IOcelotCache<T>
 | 
			
		||||
    {
 | 
			
		||||
        public void Add(string key, T value, TimeSpan ttl, string region)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void AddAndDelete(string key, T value, TimeSpan ttl, string region)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void ClearRegion(string region)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public T Get(string key, string region)
 | 
			
		||||
        {
 | 
			
		||||
            return default(T);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,29 +1,25 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Ocelot.Logging;
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using Ocelot.Middleware.Multiplexer;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Cache.Middleware
 | 
			
		||||
namespace Ocelot.Cache.Middleware
 | 
			
		||||
{
 | 
			
		||||
    using System;
 | 
			
		||||
    using System.Linq;
 | 
			
		||||
    using System.Net.Http;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using Ocelot.Logging;
 | 
			
		||||
    using Ocelot.Middleware;
 | 
			
		||||
    using System.IO;
 | 
			
		||||
 | 
			
		||||
    public class OutputCacheMiddleware : OcelotMiddleware
 | 
			
		||||
    {
 | 
			
		||||
        private readonly OcelotRequestDelegate _next;
 | 
			
		||||
        private readonly IOcelotCache<CachedResponse> _outputCache;
 | 
			
		||||
        private readonly IRegionCreator _regionCreator;
 | 
			
		||||
 | 
			
		||||
        public OutputCacheMiddleware(OcelotRequestDelegate next,
 | 
			
		||||
            IOcelotLoggerFactory loggerFactory,
 | 
			
		||||
            IOcelotCache<CachedResponse> outputCache,
 | 
			
		||||
            IRegionCreator regionCreator)
 | 
			
		||||
            IOcelotCache<CachedResponse> outputCache)
 | 
			
		||||
                :base(loggerFactory.CreateLogger<OutputCacheMiddleware>())
 | 
			
		||||
        {
 | 
			
		||||
            _next = next;
 | 
			
		||||
            _outputCache = outputCache;
 | 
			
		||||
            _regionCreator = regionCreator;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task Invoke(DownstreamContext context)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,44 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using CacheManager.Core;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Cache
 | 
			
		||||
{
 | 
			
		||||
    public class OcelotCacheManagerCache<T> : IOcelotCache<T>
 | 
			
		||||
    {
 | 
			
		||||
        private readonly ICacheManager<T> _cacheManager;
 | 
			
		||||
 | 
			
		||||
        public OcelotCacheManagerCache(ICacheManager<T> cacheManager)
 | 
			
		||||
        {
 | 
			
		||||
            _cacheManager = cacheManager;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Add(string key, T value, TimeSpan ttl, string region)
 | 
			
		||||
        {
 | 
			
		||||
            _cacheManager.Add(new CacheItem<T>(key, region, value, ExpirationMode.Absolute, ttl));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void AddAndDelete(string key, T value, TimeSpan ttl, string region)
 | 
			
		||||
        {
 | 
			
		||||
            var exists = _cacheManager.Get(key);
 | 
			
		||||
 | 
			
		||||
            if (exists != null)
 | 
			
		||||
            {
 | 
			
		||||
                _cacheManager.Remove(key);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Add(key, value, ttl, region);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public T Get(string key, string region)
 | 
			
		||||
        {
 | 
			
		||||
            return _cacheManager.Get<T>(key, region);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void ClearRegion(string region)
 | 
			
		||||
        {
 | 
			
		||||
            _cacheManager.ClearRegion(region);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,14 +1,14 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Cache
 | 
			
		||||
{
 | 
			
		||||
    public class Regions
 | 
			
		||||
    {
 | 
			
		||||
        public Regions(List<string> value)
 | 
			
		||||
        {
 | 
			
		||||
            Value = value;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public List<string> Value {get;private set;}
 | 
			
		||||
    }
 | 
			
		||||
namespace Ocelot.Cache
 | 
			
		||||
{
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
    public class Regions
 | 
			
		||||
    {
 | 
			
		||||
        public Regions(List<string> value)
 | 
			
		||||
        {
 | 
			
		||||
            Value = value;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public List<string> Value { get; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,8 @@
 | 
			
		||||
            Region = region;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public int TtlSeconds { get; private set; }
 | 
			
		||||
        public string Region {get;private set;}
 | 
			
		||||
        public int TtlSeconds { get; private set; }
 | 
			
		||||
 | 
			
		||||
        public string Region { get; private set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,3 @@
 | 
			
		||||
using CacheManager.Core;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using IdentityServer4.AccessTokenValidation;
 | 
			
		||||
@@ -14,8 +13,6 @@ namespace Ocelot.DependencyInjection
 | 
			
		||||
        IConfiguration Configuration { get; }
 | 
			
		||||
        IOcelotBuilder AddStoreOcelotConfigurationInConsul();
 | 
			
		||||
 | 
			
		||||
        IOcelotBuilder AddCacheManager(Action<ConfigurationBuilderCachePart> settings);
 | 
			
		||||
 | 
			
		||||
        IOcelotAdministrationBuilder AddAdministration(string path, string secret);
 | 
			
		||||
 | 
			
		||||
        IOcelotAdministrationBuilder AddAdministration(string path, Action<IdentityServerAuthenticationOptions> configOptions);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,5 @@
 | 
			
		||||
namespace Ocelot.DependencyInjection
 | 
			
		||||
{
 | 
			
		||||
    using CacheManager.Core;
 | 
			
		||||
    using IdentityServer4.Models;
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Microsoft.Extensions.Configuration;
 | 
			
		||||
@@ -50,118 +49,110 @@ namespace Ocelot.DependencyInjection
 | 
			
		||||
 | 
			
		||||
    public class OcelotBuilder : IOcelotBuilder
 | 
			
		||||
    {
 | 
			
		||||
        private readonly IServiceCollection _services;
 | 
			
		||||
        private readonly IConfiguration _configurationRoot;
 | 
			
		||||
 | 
			
		||||
        public IServiceCollection Services => _services;
 | 
			
		||||
 | 
			
		||||
        public IConfiguration Configuration => _configurationRoot;
 | 
			
		||||
        public IServiceCollection Services { get; }
 | 
			
		||||
        public IConfiguration Configuration { get; }
 | 
			
		||||
 | 
			
		||||
        public OcelotBuilder(IServiceCollection services, IConfiguration configurationRoot)
 | 
			
		||||
        {
 | 
			
		||||
            _configurationRoot = configurationRoot;
 | 
			
		||||
            _services = services;    
 | 
			
		||||
           
 | 
			
		||||
            //add default cache settings...
 | 
			
		||||
            Action<ConfigurationBuilderCachePart> defaultCachingSettings = x =>
 | 
			
		||||
            {
 | 
			
		||||
                x.WithDictionaryHandle();
 | 
			
		||||
            };
 | 
			
		||||
            Configuration = configurationRoot;
 | 
			
		||||
            Services = services;
 | 
			
		||||
 | 
			
		||||
            AddCacheManager(defaultCachingSettings);
 | 
			
		||||
            Services.Configure<FileConfiguration>(configurationRoot);
 | 
			
		||||
            
 | 
			
		||||
            //default no caches...
 | 
			
		||||
            Services.TryAddSingleton<IOcelotCache<FileConfiguration>, NoCache<FileConfiguration>>();
 | 
			
		||||
            Services.TryAddSingleton<IOcelotCache<CachedResponse>, NoCache<CachedResponse>>();
 | 
			
		||||
 | 
			
		||||
            //add ocelot services...
 | 
			
		||||
            _services.Configure<FileConfiguration>(configurationRoot);
 | 
			
		||||
            _services.TryAddSingleton<IHttpResponseHeaderReplacer, HttpResponseHeaderReplacer>();
 | 
			
		||||
            _services.TryAddSingleton<IHttpContextRequestHeaderReplacer, HttpContextRequestHeaderReplacer>();
 | 
			
		||||
            _services.TryAddSingleton<IHeaderFindAndReplaceCreator, HeaderFindAndReplaceCreator>();
 | 
			
		||||
            _services.TryAddSingleton<IInternalConfigurationCreator, FileInternalConfigurationCreator>();
 | 
			
		||||
            _services.TryAddSingleton<IInternalConfigurationRepository, InMemoryInternalConfigurationRepository>();
 | 
			
		||||
            _services.TryAddSingleton<IConfigurationValidator, FileConfigurationFluentValidator>();
 | 
			
		||||
            _services.TryAddSingleton<IClaimsToThingCreator, ClaimsToThingCreator>();
 | 
			
		||||
            _services.TryAddSingleton<IAuthenticationOptionsCreator, AuthenticationOptionsCreator>();
 | 
			
		||||
            _services.TryAddSingleton<IUpstreamTemplatePatternCreator, UpstreamTemplatePatternCreator>();
 | 
			
		||||
            _services.TryAddSingleton<IRequestIdKeyCreator, RequestIdKeyCreator>();
 | 
			
		||||
            _services.TryAddSingleton<IServiceProviderConfigurationCreator,ServiceProviderConfigurationCreator>();
 | 
			
		||||
            _services.TryAddSingleton<IQoSOptionsCreator, QoSOptionsCreator>();
 | 
			
		||||
            _services.TryAddSingleton<IReRouteOptionsCreator, ReRouteOptionsCreator>();
 | 
			
		||||
            _services.TryAddSingleton<IRateLimitOptionsCreator, RateLimitOptionsCreator>();
 | 
			
		||||
            _services.TryAddSingleton<IBaseUrlFinder, BaseUrlFinder>();
 | 
			
		||||
            _services.TryAddSingleton<IRegionCreator, RegionCreator>();
 | 
			
		||||
            _services.TryAddSingleton<IFileConfigurationRepository, DiskFileConfigurationRepository>();
 | 
			
		||||
            _services.TryAddSingleton<IFileConfigurationSetter, FileAndInternalConfigurationSetter>();
 | 
			
		||||
            _services.TryAddSingleton<IQosProviderHouse, QosProviderHouse>();
 | 
			
		||||
            _services.TryAddSingleton<IQoSProviderFactory, QoSProviderFactory>();
 | 
			
		||||
            _services.TryAddSingleton<IServiceDiscoveryProviderFactory, ServiceDiscoveryProviderFactory>();
 | 
			
		||||
            _services.TryAddSingleton<ILoadBalancerFactory, LoadBalancerFactory>();
 | 
			
		||||
            _services.TryAddSingleton<ILoadBalancerHouse, LoadBalancerHouse>();
 | 
			
		||||
            _services.TryAddSingleton<IOcelotLoggerFactory, AspDotNetLoggerFactory>();
 | 
			
		||||
            _services.TryAddSingleton<IRemoveOutputHeaders, RemoveOutputHeaders>();
 | 
			
		||||
            _services.TryAddSingleton<IClaimToThingConfigurationParser, ClaimToThingConfigurationParser>();
 | 
			
		||||
            _services.TryAddSingleton<IClaimsAuthoriser, ClaimsAuthoriser>();
 | 
			
		||||
            _services.TryAddSingleton<IScopesAuthoriser, ScopesAuthoriser>();
 | 
			
		||||
            _services.TryAddSingleton<IAddClaimsToRequest, AddClaimsToRequest>();
 | 
			
		||||
            _services.TryAddSingleton<IAddHeadersToRequest, AddHeadersToRequest>();
 | 
			
		||||
            _services.TryAddSingleton<IAddQueriesToRequest, AddQueriesToRequest>();
 | 
			
		||||
            _services.TryAddSingleton<IClaimsParser, ClaimsParser>();
 | 
			
		||||
            _services.TryAddSingleton<IUrlPathToUrlTemplateMatcher, RegExUrlMatcher>();
 | 
			
		||||
            _services.TryAddSingleton<IPlaceholderNameAndValueFinder, UrlPathPlaceholderNameAndValueFinder>();
 | 
			
		||||
            _services.TryAddSingleton<IDownstreamPathPlaceholderReplacer, DownstreamTemplatePathPlaceholderReplacer>();
 | 
			
		||||
            _services.AddSingleton<IDownstreamRouteProvider, DownstreamRouteFinder>();
 | 
			
		||||
            _services.AddSingleton<IDownstreamRouteProvider, Ocelot.DownstreamRouteFinder.Finder.DownstreamRouteCreator>();
 | 
			
		||||
            _services.TryAddSingleton<IDownstreamRouteProviderFactory, Ocelot.DownstreamRouteFinder.Finder.DownstreamRouteProviderFactory>();
 | 
			
		||||
            _services.TryAddSingleton<IHttpRequester, HttpClientHttpRequester>();
 | 
			
		||||
            _services.TryAddSingleton<IHttpResponder, HttpContextResponder>();
 | 
			
		||||
            _services.TryAddSingleton<IErrorsToHttpStatusCodeMapper, ErrorsToHttpStatusCodeMapper>();
 | 
			
		||||
            _services.TryAddSingleton<IRateLimitCounterHandler, MemoryCacheRateLimitCounterHandler>();
 | 
			
		||||
            _services.TryAddSingleton<IHttpClientCache, MemoryHttpClientCache>();
 | 
			
		||||
            _services.TryAddSingleton<IRequestMapper, RequestMapper>();
 | 
			
		||||
            _services.TryAddSingleton<IHttpHandlerOptionsCreator, HttpHandlerOptionsCreator>();
 | 
			
		||||
            _services.TryAddSingleton<IDownstreamAddressesCreator, DownstreamAddressesCreator>();
 | 
			
		||||
            _services.TryAddSingleton<IDelegatingHandlerHandlerFactory, DelegatingHandlerHandlerFactory>();
 | 
			
		||||
            Services.TryAddSingleton<IHttpResponseHeaderReplacer, HttpResponseHeaderReplacer>();
 | 
			
		||||
            Services.TryAddSingleton<IHttpContextRequestHeaderReplacer, HttpContextRequestHeaderReplacer>();
 | 
			
		||||
            Services.TryAddSingleton<IHeaderFindAndReplaceCreator, HeaderFindAndReplaceCreator>();
 | 
			
		||||
            Services.TryAddSingleton<IInternalConfigurationCreator, FileInternalConfigurationCreator>();
 | 
			
		||||
            Services.TryAddSingleton<IInternalConfigurationRepository, InMemoryInternalConfigurationRepository>();
 | 
			
		||||
            Services.TryAddSingleton<IConfigurationValidator, FileConfigurationFluentValidator>();
 | 
			
		||||
            Services.TryAddSingleton<IClaimsToThingCreator, ClaimsToThingCreator>();
 | 
			
		||||
            Services.TryAddSingleton<IAuthenticationOptionsCreator, AuthenticationOptionsCreator>();
 | 
			
		||||
            Services.TryAddSingleton<IUpstreamTemplatePatternCreator, UpstreamTemplatePatternCreator>();
 | 
			
		||||
            Services.TryAddSingleton<IRequestIdKeyCreator, RequestIdKeyCreator>();
 | 
			
		||||
            Services.TryAddSingleton<IServiceProviderConfigurationCreator,ServiceProviderConfigurationCreator>();
 | 
			
		||||
            Services.TryAddSingleton<IQoSOptionsCreator, QoSOptionsCreator>();
 | 
			
		||||
            Services.TryAddSingleton<IReRouteOptionsCreator, ReRouteOptionsCreator>();
 | 
			
		||||
            Services.TryAddSingleton<IRateLimitOptionsCreator, RateLimitOptionsCreator>();
 | 
			
		||||
            Services.TryAddSingleton<IBaseUrlFinder, BaseUrlFinder>();
 | 
			
		||||
            Services.TryAddSingleton<IRegionCreator, RegionCreator>();
 | 
			
		||||
            Services.TryAddSingleton<IFileConfigurationRepository, DiskFileConfigurationRepository>();
 | 
			
		||||
            Services.TryAddSingleton<IFileConfigurationSetter, FileAndInternalConfigurationSetter>();
 | 
			
		||||
            Services.TryAddSingleton<IQosProviderHouse, QosProviderHouse>();
 | 
			
		||||
            Services.TryAddSingleton<IQoSProviderFactory, QoSProviderFactory>();
 | 
			
		||||
            Services.TryAddSingleton<IServiceDiscoveryProviderFactory, ServiceDiscoveryProviderFactory>();
 | 
			
		||||
            Services.TryAddSingleton<ILoadBalancerFactory, LoadBalancerFactory>();
 | 
			
		||||
            Services.TryAddSingleton<ILoadBalancerHouse, LoadBalancerHouse>();
 | 
			
		||||
            Services.TryAddSingleton<IOcelotLoggerFactory, AspDotNetLoggerFactory>();
 | 
			
		||||
            Services.TryAddSingleton<IRemoveOutputHeaders, RemoveOutputHeaders>();
 | 
			
		||||
            Services.TryAddSingleton<IClaimToThingConfigurationParser, ClaimToThingConfigurationParser>();
 | 
			
		||||
            Services.TryAddSingleton<IClaimsAuthoriser, ClaimsAuthoriser>();
 | 
			
		||||
            Services.TryAddSingleton<IScopesAuthoriser, ScopesAuthoriser>();
 | 
			
		||||
            Services.TryAddSingleton<IAddClaimsToRequest, AddClaimsToRequest>();
 | 
			
		||||
            Services.TryAddSingleton<IAddHeadersToRequest, AddHeadersToRequest>();
 | 
			
		||||
            Services.TryAddSingleton<IAddQueriesToRequest, AddQueriesToRequest>();
 | 
			
		||||
            Services.TryAddSingleton<IClaimsParser, ClaimsParser>();
 | 
			
		||||
            Services.TryAddSingleton<IUrlPathToUrlTemplateMatcher, RegExUrlMatcher>();
 | 
			
		||||
            Services.TryAddSingleton<IPlaceholderNameAndValueFinder, UrlPathPlaceholderNameAndValueFinder>();
 | 
			
		||||
            Services.TryAddSingleton<IDownstreamPathPlaceholderReplacer, DownstreamTemplatePathPlaceholderReplacer>();
 | 
			
		||||
            Services.AddSingleton<IDownstreamRouteProvider, DownstreamRouteFinder>();
 | 
			
		||||
            Services.AddSingleton<IDownstreamRouteProvider, DownstreamRouteCreator>();
 | 
			
		||||
            Services.TryAddSingleton<IDownstreamRouteProviderFactory, DownstreamRouteProviderFactory>();
 | 
			
		||||
            Services.TryAddSingleton<IHttpRequester, HttpClientHttpRequester>();
 | 
			
		||||
            Services.TryAddSingleton<IHttpResponder, HttpContextResponder>();
 | 
			
		||||
            Services.TryAddSingleton<IErrorsToHttpStatusCodeMapper, ErrorsToHttpStatusCodeMapper>();
 | 
			
		||||
            Services.TryAddSingleton<IRateLimitCounterHandler, MemoryCacheRateLimitCounterHandler>();
 | 
			
		||||
            Services.TryAddSingleton<IHttpClientCache, MemoryHttpClientCache>();
 | 
			
		||||
            Services.TryAddSingleton<IRequestMapper, RequestMapper>();
 | 
			
		||||
            Services.TryAddSingleton<IHttpHandlerOptionsCreator, HttpHandlerOptionsCreator>();
 | 
			
		||||
            Services.TryAddSingleton<IDownstreamAddressesCreator, DownstreamAddressesCreator>();
 | 
			
		||||
            Services.TryAddSingleton<IDelegatingHandlerHandlerFactory, DelegatingHandlerHandlerFactory>();
 | 
			
		||||
 | 
			
		||||
            if (UsingEurekaServiceDiscoveryProvider(configurationRoot))
 | 
			
		||||
            {
 | 
			
		||||
                _services.AddDiscoveryClient(configurationRoot);
 | 
			
		||||
                Services.AddDiscoveryClient(configurationRoot);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                _services.TryAddSingleton<IDiscoveryClient, FakeEurekaDiscoveryClient>();
 | 
			
		||||
                Services.TryAddSingleton<IDiscoveryClient, FakeEurekaDiscoveryClient>();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            _services.TryAddSingleton<IHttpRequester, HttpClientHttpRequester>();
 | 
			
		||||
            Services.TryAddSingleton<IHttpRequester, HttpClientHttpRequester>();
 | 
			
		||||
 | 
			
		||||
            // 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
 | 
			
		||||
            _services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
 | 
			
		||||
            _services.TryAddSingleton<IRequestScopedDataRepository, HttpDataRepository>();
 | 
			
		||||
            _services.AddMemoryCache();
 | 
			
		||||
            _services.TryAddSingleton<OcelotDiagnosticListener>();
 | 
			
		||||
            Services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
 | 
			
		||||
            Services.TryAddSingleton<IRequestScopedDataRepository, HttpDataRepository>();
 | 
			
		||||
            Services.AddMemoryCache();
 | 
			
		||||
            Services.TryAddSingleton<OcelotDiagnosticListener>();
 | 
			
		||||
 | 
			
		||||
            //add asp.net services..
 | 
			
		||||
            var assembly = typeof(FileConfigurationController).GetTypeInfo().Assembly;
 | 
			
		||||
 | 
			
		||||
            _services.AddMvcCore()
 | 
			
		||||
            Services.AddMvcCore()
 | 
			
		||||
                .AddApplicationPart(assembly)
 | 
			
		||||
                .AddControllersAsServices()
 | 
			
		||||
                .AddAuthorization()
 | 
			
		||||
                .AddJsonFormatters();
 | 
			
		||||
 | 
			
		||||
            _services.AddLogging();
 | 
			
		||||
            _services.AddMiddlewareAnalysis();
 | 
			
		||||
            _services.AddWebEncoders();
 | 
			
		||||
            Services.AddLogging();
 | 
			
		||||
            Services.AddMiddlewareAnalysis();
 | 
			
		||||
            Services.AddWebEncoders();
 | 
			
		||||
 | 
			
		||||
            _services.TryAddSingleton<IMultiplexer, Multiplexer>();
 | 
			
		||||
            _services.TryAddSingleton<IResponseAggregator, SimpleJsonResponseAggregator>();
 | 
			
		||||
            _services.AddSingleton<ITracingHandlerFactory, TracingHandlerFactory>();
 | 
			
		||||
            _services.TryAddSingleton<IFileConfigurationPollerOptions, InMemoryFileConfigurationPollerOptions>();
 | 
			
		||||
            _services.TryAddSingleton<IAddHeadersToResponse, AddHeadersToResponse>();
 | 
			
		||||
            _services.TryAddSingleton<IPlaceholders, Placeholders>();
 | 
			
		||||
            _services.TryAddSingleton<IConsulClientFactory, ConsulClientFactory>();
 | 
			
		||||
            _services.TryAddSingleton<IResponseAggregatorFactory, InMemoryResponseAggregatorFactory>();
 | 
			
		||||
            _services.TryAddSingleton<IDefinedAggregatorProvider, ServiceLocatorDefinedAggregatorProvider>();
 | 
			
		||||
            _services.TryAddSingleton<IDownstreamRequestCreator, DownstreamRequestCreator>();
 | 
			
		||||
            _services.TryAddSingleton<IFrameworkDescription, FrameworkDescription>();
 | 
			
		||||
            Services.TryAddSingleton<IMultiplexer, Multiplexer>();
 | 
			
		||||
            Services.TryAddSingleton<IResponseAggregator, SimpleJsonResponseAggregator>();
 | 
			
		||||
            Services.AddSingleton<ITracingHandlerFactory, TracingHandlerFactory>();
 | 
			
		||||
            Services.TryAddSingleton<IFileConfigurationPollerOptions, InMemoryFileConfigurationPollerOptions>();
 | 
			
		||||
            Services.TryAddSingleton<IAddHeadersToResponse, AddHeadersToResponse>();
 | 
			
		||||
            Services.TryAddSingleton<IPlaceholders, Placeholders>();
 | 
			
		||||
            Services.TryAddSingleton<IConsulClientFactory, ConsulClientFactory>();
 | 
			
		||||
            Services.TryAddSingleton<IResponseAggregatorFactory, InMemoryResponseAggregatorFactory>();
 | 
			
		||||
            Services.TryAddSingleton<IDefinedAggregatorProvider, ServiceLocatorDefinedAggregatorProvider>();
 | 
			
		||||
            Services.TryAddSingleton<IDownstreamRequestCreator, DownstreamRequestCreator>();
 | 
			
		||||
            Services.TryAddSingleton<IFrameworkDescription, FrameworkDescription>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IOcelotAdministrationBuilder AddAdministration(string path, string secret)
 | 
			
		||||
@@ -176,8 +167,8 @@ namespace Ocelot.DependencyInjection
 | 
			
		||||
                AddIdentityServer(identityServerConfiguration, administrationPath);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            _services.AddSingleton<IAdministrationPath>(administrationPath);
 | 
			
		||||
            return new OcelotAdministrationBuilder(_services, _configurationRoot);
 | 
			
		||||
            Services.AddSingleton<IAdministrationPath>(administrationPath);
 | 
			
		||||
            return new OcelotAdministrationBuilder(Services, Configuration);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IOcelotAdministrationBuilder AddAdministration(string path, Action<IdentityServerAuthenticationOptions> configureOptions)
 | 
			
		||||
@@ -189,21 +180,21 @@ namespace Ocelot.DependencyInjection
 | 
			
		||||
                AddIdentityServer(configureOptions);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            _services.AddSingleton<IAdministrationPath>(administrationPath);
 | 
			
		||||
            return new OcelotAdministrationBuilder(_services, _configurationRoot);
 | 
			
		||||
            Services.AddSingleton<IAdministrationPath>(administrationPath);
 | 
			
		||||
            return new OcelotAdministrationBuilder(Services, Configuration);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IOcelotBuilder AddSingletonDefinedAggregator<T>() 
 | 
			
		||||
            where T : class, IDefinedAggregator
 | 
			
		||||
        {
 | 
			
		||||
            _services.AddSingleton<IDefinedAggregator, T>();
 | 
			
		||||
            Services.AddSingleton<IDefinedAggregator, T>();
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IOcelotBuilder AddTransientDefinedAggregator<T>() 
 | 
			
		||||
            where T : class, IDefinedAggregator
 | 
			
		||||
        {
 | 
			
		||||
            _services.AddTransient<IDefinedAggregator, T>();
 | 
			
		||||
            Services.AddTransient<IDefinedAggregator, T>();
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -212,15 +203,15 @@ namespace Ocelot.DependencyInjection
 | 
			
		||||
        {
 | 
			
		||||
            if(global)
 | 
			
		||||
            {
 | 
			
		||||
                _services.AddTransient<THandler>();
 | 
			
		||||
                _services.AddTransient<GlobalDelegatingHandler>(s => {
 | 
			
		||||
                Services.AddTransient<THandler>();
 | 
			
		||||
                Services.AddTransient<GlobalDelegatingHandler>(s => {
 | 
			
		||||
                    var service = s.GetService<THandler>();
 | 
			
		||||
                    return new GlobalDelegatingHandler(service);
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                _services.AddTransient<DelegatingHandler, THandler>();
 | 
			
		||||
                Services.AddTransient<DelegatingHandler, THandler>();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return this;
 | 
			
		||||
@@ -228,59 +219,33 @@ namespace Ocelot.DependencyInjection
 | 
			
		||||
 | 
			
		||||
        public IOcelotBuilder AddStoreOcelotConfigurationInConsul()
 | 
			
		||||
        {
 | 
			
		||||
            _services.AddHostedService<FileConfigurationPoller>();
 | 
			
		||||
            _services.AddSingleton<IFileConfigurationRepository, ConsulFileConfigurationRepository>();
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public IOcelotBuilder AddCacheManager(Action<ConfigurationBuilderCachePart> settings)
 | 
			
		||||
        {
 | 
			
		||||
            var cacheManagerOutputCache = CacheFactory.Build<CachedResponse>("OcelotOutputCache", settings);
 | 
			
		||||
            var ocelotOutputCacheManager = new OcelotCacheManagerCache<CachedResponse>(cacheManagerOutputCache);
 | 
			
		||||
 | 
			
		||||
            _services.RemoveAll(typeof(ICacheManager<CachedResponse>));
 | 
			
		||||
            _services.RemoveAll(typeof(IOcelotCache<CachedResponse>));
 | 
			
		||||
            _services.AddSingleton<ICacheManager<CachedResponse>>(cacheManagerOutputCache);
 | 
			
		||||
            _services.AddSingleton<IOcelotCache<CachedResponse>>(ocelotOutputCacheManager);
 | 
			
		||||
 | 
			
		||||
            var ocelotConfigCacheManagerOutputCache = CacheFactory.Build<IInternalConfiguration>("OcelotConfigurationCache", settings);
 | 
			
		||||
            var ocelotConfigCacheManager = new OcelotCacheManagerCache<IInternalConfiguration>(ocelotConfigCacheManagerOutputCache);
 | 
			
		||||
            _services.RemoveAll(typeof(ICacheManager<IInternalConfiguration>));
 | 
			
		||||
            _services.RemoveAll(typeof(IOcelotCache<IInternalConfiguration>));
 | 
			
		||||
            _services.AddSingleton<ICacheManager<IInternalConfiguration>>(ocelotConfigCacheManagerOutputCache);
 | 
			
		||||
            _services.AddSingleton<IOcelotCache<IInternalConfiguration>>(ocelotConfigCacheManager);
 | 
			
		||||
 | 
			
		||||
            var fileConfigCacheManagerOutputCache = CacheFactory.Build<FileConfiguration>("FileConfigurationCache", settings);
 | 
			
		||||
            var fileConfigCacheManager = new OcelotCacheManagerCache<FileConfiguration>(fileConfigCacheManagerOutputCache);
 | 
			
		||||
            _services.RemoveAll(typeof(ICacheManager<FileConfiguration>));
 | 
			
		||||
            _services.RemoveAll(typeof(IOcelotCache<FileConfiguration>));
 | 
			
		||||
            _services.AddSingleton<ICacheManager<FileConfiguration>>(fileConfigCacheManagerOutputCache);
 | 
			
		||||
            _services.AddSingleton<IOcelotCache<FileConfiguration>>(fileConfigCacheManager);
 | 
			
		||||
            Services.AddHostedService<FileConfigurationPoller>();
 | 
			
		||||
            Services.AddSingleton<IFileConfigurationRepository, ConsulFileConfigurationRepository>();
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void AddIdentityServer(Action<IdentityServerAuthenticationOptions> configOptions)
 | 
			
		||||
        {
 | 
			
		||||
            _services
 | 
			
		||||
            Services
 | 
			
		||||
                .AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
 | 
			
		||||
                .AddIdentityServerAuthentication(configOptions);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void AddIdentityServer(IIdentityServerConfiguration identityServerConfiguration, IAdministrationPath adminPath) 
 | 
			
		||||
        {
 | 
			
		||||
            _services.TryAddSingleton<IIdentityServerConfiguration>(identityServerConfiguration);
 | 
			
		||||
            var identityServerBuilder = _services
 | 
			
		||||
            Services.TryAddSingleton<IIdentityServerConfiguration>(identityServerConfiguration);
 | 
			
		||||
            var identityServerBuilder = Services
 | 
			
		||||
                .AddIdentityServer(o => {
 | 
			
		||||
                    o.IssuerUri = "Ocelot";
 | 
			
		||||
                })
 | 
			
		||||
                .AddInMemoryApiResources(Resources(identityServerConfiguration))
 | 
			
		||||
                .AddInMemoryClients(Client(identityServerConfiguration));
 | 
			
		||||
 | 
			
		||||
            var urlFinder = new BaseUrlFinder(_configurationRoot);
 | 
			
		||||
            var urlFinder = new BaseUrlFinder(Configuration);
 | 
			
		||||
            var baseSchemeUrlAndPort = urlFinder.Find();
 | 
			
		||||
            JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();            
 | 
			
		||||
 | 
			
		||||
            _services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
 | 
			
		||||
            Services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
 | 
			
		||||
                .AddIdentityServerAuthentication(o =>
 | 
			
		||||
                {
 | 
			
		||||
                    o.Authority = baseSchemeUrlAndPort + adminPath.Path;
 | 
			
		||||
 
 | 
			
		||||
@@ -45,9 +45,6 @@
 | 
			
		||||
      <PrivateAssets>all</PrivateAssets>
 | 
			
		||||
    </PackageReference>
 | 
			
		||||
    <PackageReference Include="System.Text.RegularExpressions" Version="4.3.0" />
 | 
			
		||||
    <PackageReference Include="CacheManager.Core" Version="1.1.2" />
 | 
			
		||||
    <PackageReference Include="CacheManager.Microsoft.Extensions.Configuration" Version="1.1.2" />
 | 
			
		||||
    <PackageReference Include="CacheManager.Microsoft.Extensions.Logging" Version="1.1.2" />
 | 
			
		||||
    <PackageReference Include="Consul" Version="0.7.2.5" />
 | 
			
		||||
    <PackageReference Include="Polly" Version="6.0.1" />
 | 
			
		||||
    <PackageReference Include="IdentityServer4" Version="2.2.0" />
 | 
			
		||||
 
 | 
			
		||||
@@ -1,137 +0,0 @@
 | 
			
		||||
using CacheManager.Core;
 | 
			
		||||
using CacheManager.Core.Internal;
 | 
			
		||||
using CacheManager.Core.Logging;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Concurrent;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using static CacheManager.Core.Utility.Guard;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.AcceptanceTests.Caching
 | 
			
		||||
{
 | 
			
		||||
    public class InMemoryJsonHandle<TCacheValue> : BaseCacheHandle<TCacheValue>
 | 
			
		||||
    {
 | 
			
		||||
        private readonly ICacheSerializer _serializer;
 | 
			
		||||
        private readonly ConcurrentDictionary<string, Tuple<Type, byte[]>> _cache;
 | 
			
		||||
 | 
			
		||||
        public InMemoryJsonHandle(
 | 
			
		||||
            ICacheManagerConfiguration managerConfiguration,
 | 
			
		||||
            CacheHandleConfiguration configuration,
 | 
			
		||||
            ICacheSerializer serializer,
 | 
			
		||||
            ILoggerFactory loggerFactory) : base(managerConfiguration, configuration)
 | 
			
		||||
        {
 | 
			
		||||
            _cache = new ConcurrentDictionary<string, Tuple<Type, byte[]>>();
 | 
			
		||||
            _serializer = serializer;
 | 
			
		||||
            Logger = loggerFactory.CreateLogger(this);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override int Count => _cache.Count;
 | 
			
		||||
 | 
			
		||||
        protected override ILogger Logger { get; }
 | 
			
		||||
 | 
			
		||||
        public override void Clear() => _cache.Clear();
 | 
			
		||||
 | 
			
		||||
        public override void ClearRegion(string region)
 | 
			
		||||
        {
 | 
			
		||||
            NotNullOrWhiteSpace(region, nameof(region));
 | 
			
		||||
 | 
			
		||||
            var key = string.Concat(region, ":");
 | 
			
		||||
            foreach (var item in _cache.Where(p => p.Key.StartsWith(key, StringComparison.OrdinalIgnoreCase)))
 | 
			
		||||
            {
 | 
			
		||||
                _cache.TryRemove(item.Key, out Tuple<Type, byte[]> val);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override bool Exists(string key)
 | 
			
		||||
        {
 | 
			
		||||
            NotNullOrWhiteSpace(key, nameof(key));
 | 
			
		||||
 | 
			
		||||
            return _cache.ContainsKey(key);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public override bool Exists(string key, string region)
 | 
			
		||||
        {
 | 
			
		||||
            NotNullOrWhiteSpace(region, nameof(region));
 | 
			
		||||
            var fullKey = GetKey(key, region);
 | 
			
		||||
            return _cache.ContainsKey(fullKey);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override bool AddInternalPrepared(CacheItem<TCacheValue> item)
 | 
			
		||||
        {
 | 
			
		||||
            NotNull(item, nameof(item));
 | 
			
		||||
 | 
			
		||||
            var key = GetKey(item.Key, item.Region);
 | 
			
		||||
 | 
			
		||||
            var serializedItem = _serializer.SerializeCacheItem(item);
 | 
			
		||||
 | 
			
		||||
            return _cache.TryAdd(key, new Tuple<Type, byte[]>(item.Value.GetType(), serializedItem));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override CacheItem<TCacheValue> GetCacheItemInternal(string key) => GetCacheItemInternal(key, null);
 | 
			
		||||
 | 
			
		||||
        protected override CacheItem<TCacheValue> GetCacheItemInternal(string key, string region)
 | 
			
		||||
        {
 | 
			
		||||
            var fullKey = GetKey(key, region);
 | 
			
		||||
 | 
			
		||||
            CacheItem<TCacheValue> deserializedResult = null;
 | 
			
		||||
 | 
			
		||||
            if (_cache.TryGetValue(fullKey, out Tuple<Type, byte[]> result))
 | 
			
		||||
            {
 | 
			
		||||
                deserializedResult = _serializer.DeserializeCacheItem<TCacheValue>(result.Item2, result.Item1);
 | 
			
		||||
 | 
			
		||||
                if (deserializedResult.ExpirationMode != ExpirationMode.None && IsExpired(deserializedResult, DateTime.UtcNow))
 | 
			
		||||
                {
 | 
			
		||||
                    _cache.TryRemove(fullKey, out Tuple<Type, byte[]> removeResult);
 | 
			
		||||
                    TriggerCacheSpecificRemove(key, region, CacheItemRemovedReason.Expired, deserializedResult.Value);
 | 
			
		||||
                    return null;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return deserializedResult;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override void PutInternalPrepared(CacheItem<TCacheValue> item)
 | 
			
		||||
        {
 | 
			
		||||
            NotNull(item, nameof(item));
 | 
			
		||||
 | 
			
		||||
            var serializedItem = _serializer.SerializeCacheItem<TCacheValue>(item);
 | 
			
		||||
 | 
			
		||||
            _cache[GetKey(item.Key, item.Region)] = new Tuple<Type, byte[]>(item.Value.GetType(), serializedItem);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override bool RemoveInternal(string key) => RemoveInternal(key, null);
 | 
			
		||||
 | 
			
		||||
        protected override bool RemoveInternal(string key, string region)
 | 
			
		||||
        {
 | 
			
		||||
            var fullKey = GetKey(key, region);
 | 
			
		||||
            return _cache.TryRemove(fullKey, out Tuple<Type, byte[]> val);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static string GetKey(string key, string region)
 | 
			
		||||
        {
 | 
			
		||||
            NotNullOrWhiteSpace(key, nameof(key));
 | 
			
		||||
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(region))
 | 
			
		||||
            {
 | 
			
		||||
                return key;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return string.Concat(region, ":", key);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static bool IsExpired(CacheItem<TCacheValue> item, DateTime now)
 | 
			
		||||
        {
 | 
			
		||||
            if (item.ExpirationMode == ExpirationMode.Absolute
 | 
			
		||||
                && item.CreatedUtc.Add(item.ExpirationTimeout) < now)
 | 
			
		||||
            {
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
            else if (item.ExpirationMode == ExpirationMode.Sliding
 | 
			
		||||
                && item.LastAccessedUtc.Add(item.ExpirationTimeout) < now)
 | 
			
		||||
            {
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,225 +0,0 @@
 | 
			
		||||
namespace Ocelot.AcceptanceTests
 | 
			
		||||
{
 | 
			
		||||
    using System;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Net;
 | 
			
		||||
    using System.Threading;
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Ocelot.Configuration.File;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
 | 
			
		||||
    public class CachingTests : IDisposable
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Steps _steps;
 | 
			
		||||
        private readonly ServiceHandler _serviceHandler;
 | 
			
		||||
 | 
			
		||||
        public CachingTests()
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler = new ServiceHandler();
 | 
			
		||||
            _steps = new Steps();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_cached_response()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51899,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            FileCacheOptions = new FileCacheOptions
 | 
			
		||||
                            {
 | 
			
		||||
                                TtlSeconds = 100
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51899", 200, "Hello from Laura", null, null))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .Given(x => x.GivenTheServiceNowReturns("http://localhost:51899", 200, "Hello from Tom"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .And(x => _steps.ThenTheContentLengthIs(16))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_cached_response_with_expires_header()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 52839,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            FileCacheOptions = new FileCacheOptions
 | 
			
		||||
                            {
 | 
			
		||||
                                TtlSeconds = 100
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:52839", 200, "Hello from Laura", "Expires", "-1"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .Given(x => x.GivenTheServiceNowReturns("http://localhost:52839", 200, "Hello from Tom"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .And(x => _steps.ThenTheContentLengthIs(16))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyHeaderIs("Expires", "-1"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_cached_response_when_using_jsonserialized_cache()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51899,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            FileCacheOptions = new FileCacheOptions
 | 
			
		||||
                            {
 | 
			
		||||
                                TtlSeconds = 100
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51899", 200, "Hello from Laura", null, null))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunningUsingJsonSerializedCache())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .Given(x => x.GivenTheServiceNowReturns("http://localhost:51899", 200, "Hello from Tom"))
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_not_return_cached_response_as_ttl_expires()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51899,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                            FileCacheOptions = new FileCacheOptions
 | 
			
		||||
                            {
 | 
			
		||||
                                TtlSeconds = 1
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51899", 200, "Hello from Laura", null, null))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunning())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .Given(x => x.GivenTheServiceNowReturns("http://localhost:51899", 200, "Hello from Tom"))
 | 
			
		||||
                .And(x => x.GivenTheCacheExpires())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Tom"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheCacheExpires()
 | 
			
		||||
        {
 | 
			
		||||
            Thread.Sleep(1000);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheServiceNowReturns(string url, int statusCode, string responseBody)
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler.Dispose();
 | 
			
		||||
            GivenThereIsAServiceRunningOn(url, statusCode, responseBody, null, null);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereIsAServiceRunningOn(string url, int statusCode, string responseBody, string key, string value)
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler.GivenThereIsAServiceRunningOn(url, async context =>
 | 
			
		||||
            {
 | 
			
		||||
                if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(key))
 | 
			
		||||
                {
 | 
			
		||||
                    context.Response.Headers.Add(key, value);
 | 
			
		||||
                }
 | 
			
		||||
                context.Response.StatusCode = statusCode;
 | 
			
		||||
                await context.Response.WriteAsync(responseBody);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void Dispose()
 | 
			
		||||
        {
 | 
			
		||||
            _serviceHandler?.Dispose();
 | 
			
		||||
            _steps.Dispose();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -17,6 +17,8 @@ using static Ocelot.Infrastructure.Wait;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.AcceptanceTests
 | 
			
		||||
{
 | 
			
		||||
    using Cache;
 | 
			
		||||
 | 
			
		||||
    public class ConfigurationInConsulTests : IDisposable
 | 
			
		||||
    {
 | 
			
		||||
        private IWebHost _builder;
 | 
			
		||||
@@ -76,51 +78,6 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_return_response_200_with_simple_url_when_using_jsonserialized_cache()
 | 
			
		||||
        {
 | 
			
		||||
            var configuration = new FileConfiguration
 | 
			
		||||
            {
 | 
			
		||||
                ReRoutes = new List<FileReRoute>
 | 
			
		||||
                    {
 | 
			
		||||
                        new FileReRoute
 | 
			
		||||
                        {
 | 
			
		||||
                            DownstreamPathTemplate = "/",
 | 
			
		||||
                            DownstreamScheme = "http",
 | 
			
		||||
                            DownstreamHostAndPorts = new List<FileHostAndPort>
 | 
			
		||||
                            {
 | 
			
		||||
                                new FileHostAndPort
 | 
			
		||||
                                {
 | 
			
		||||
                                    Host = "localhost",
 | 
			
		||||
                                    Port = 51779,
 | 
			
		||||
                                }
 | 
			
		||||
                            },
 | 
			
		||||
                            UpstreamPathTemplate = "/",
 | 
			
		||||
                            UpstreamHttpMethod = new List<string> { "Get" },
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                GlobalConfiguration = new FileGlobalConfiguration()
 | 
			
		||||
                {
 | 
			
		||||
                    ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
 | 
			
		||||
                    {
 | 
			
		||||
                        Host = "localhost",
 | 
			
		||||
                        Port = 9502
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var fakeConsulServiceDiscoveryUrl = "http://localhost:9502";
 | 
			
		||||
 | 
			
		||||
            this.Given(x => GivenThereIsAFakeConsulServiceDiscoveryProvider(fakeConsulServiceDiscoveryUrl, ""))
 | 
			
		||||
                .And(x => x.GivenThereIsAServiceRunningOn("http://localhost:51779", "", 200, "Hello from Laura"))
 | 
			
		||||
                .And(x => _steps.GivenThereIsAConfiguration(configuration))
 | 
			
		||||
                .And(x => _steps.GivenOcelotIsRunningUsingConsulToStoreConfigAndJsonSerializedCache())
 | 
			
		||||
                .When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
 | 
			
		||||
                .Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
 | 
			
		||||
                .And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_load_configuration_out_of_consul()
 | 
			
		||||
        {
 | 
			
		||||
@@ -485,5 +442,28 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
            _builder?.Dispose();
 | 
			
		||||
            _steps.Dispose();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        class FakeCache : IOcelotCache<FileConfiguration>
 | 
			
		||||
        {
 | 
			
		||||
            public void Add(string key, FileConfiguration value, TimeSpan ttl, string region)
 | 
			
		||||
            {
 | 
			
		||||
                throw new NotImplementedException();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public void AddAndDelete(string key, FileConfiguration value, TimeSpan ttl, string region)
 | 
			
		||||
            {
 | 
			
		||||
                throw new NotImplementedException();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public FileConfiguration Get(string key, string region)
 | 
			
		||||
            {
 | 
			
		||||
                throw new NotImplementedException();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public void ClearRegion(string region)
 | 
			
		||||
            {
 | 
			
		||||
                throw new NotImplementedException();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -32,7 +32,6 @@
 | 
			
		||||
    <Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <PackageReference Include="CacheManager.Serialization.Json" Version="1.1.2" />
 | 
			
		||||
    <PackageReference Include="Microsoft.AspNetCore.All" Version="2.1.1" />
 | 
			
		||||
    <PackageReference Include="Microsoft.AspNetCore.TestHost" Version="2.1.1" />
 | 
			
		||||
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.2" />
 | 
			
		||||
 
 | 
			
		||||
@@ -1,40 +1,35 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.IO;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Net;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using System.Net.Http.Headers;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using CacheManager.Core;
 | 
			
		||||
using IdentityServer4.AccessTokenValidation;
 | 
			
		||||
using Microsoft.AspNetCore.Builder;
 | 
			
		||||
using Microsoft.AspNetCore.Hosting;
 | 
			
		||||
using Microsoft.AspNetCore.TestHost;
 | 
			
		||||
using Microsoft.Extensions.Configuration;
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
using Microsoft.Extensions.Logging;
 | 
			
		||||
using Newtonsoft.Json;
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
using Ocelot.DependencyInjection;
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using ConfigurationBuilder = Microsoft.Extensions.Configuration.ConfigurationBuilder;
 | 
			
		||||
using Ocelot.AcceptanceTests.Caching;
 | 
			
		||||
using System.IO.Compression;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using static Ocelot.AcceptanceTests.HttpDelegatingHandlersTests;
 | 
			
		||||
using Ocelot.Requester;
 | 
			
		||||
using Ocelot.Middleware.Multiplexer;
 | 
			
		||||
using static Ocelot.Infrastructure.Wait;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.AcceptanceTests
 | 
			
		||||
namespace Ocelot.AcceptanceTests
 | 
			
		||||
{
 | 
			
		||||
    using Butterfly;
 | 
			
		||||
    using System;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.IO;
 | 
			
		||||
    using System.Linq;
 | 
			
		||||
    using System.Net;
 | 
			
		||||
    using System.Net.Http;
 | 
			
		||||
    using System.Net.Http.Headers;
 | 
			
		||||
    using System.Threading;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using IdentityServer4.AccessTokenValidation;
 | 
			
		||||
    using Microsoft.AspNetCore.Builder;
 | 
			
		||||
    using Microsoft.AspNetCore.Hosting;
 | 
			
		||||
    using Microsoft.AspNetCore.TestHost;
 | 
			
		||||
    using Microsoft.Extensions.Configuration;
 | 
			
		||||
    using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
    using Microsoft.Extensions.Logging;
 | 
			
		||||
    using Newtonsoft.Json;
 | 
			
		||||
    using Ocelot.Configuration.File;
 | 
			
		||||
    using Ocelot.DependencyInjection;
 | 
			
		||||
    using Ocelot.Middleware;
 | 
			
		||||
    using Shouldly;
 | 
			
		||||
    using ConfigurationBuilder = Microsoft.Extensions.Configuration.ConfigurationBuilder;
 | 
			
		||||
    using System.IO.Compression;
 | 
			
		||||
    using System.Text;
 | 
			
		||||
    using static Ocelot.AcceptanceTests.HttpDelegatingHandlersTests;
 | 
			
		||||
    using Ocelot.Middleware.Multiplexer;
 | 
			
		||||
    using static Ocelot.Infrastructure.Wait;
 | 
			
		||||
    using Configuration.Repository;
 | 
			
		||||
    using Microsoft.Net.Http.Headers;
 | 
			
		||||
    using Ocelot.Configuration.Creator;
 | 
			
		||||
    using CookieHeaderValue = System.Net.Http.Headers.CookieHeaderValue;
 | 
			
		||||
    using MediaTypeHeaderValue = System.Net.Http.Headers.MediaTypeHeaderValue;
 | 
			
		||||
 | 
			
		||||
    public class Steps : IDisposable
 | 
			
		||||
@@ -44,7 +39,6 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
        private HttpResponseMessage _response;
 | 
			
		||||
        private HttpContent _postContent;
 | 
			
		||||
        private BearerToken _token;
 | 
			
		||||
        public HttpClient OcelotClient => _ocelotClient;
 | 
			
		||||
        public string RequestIdKey = "OcRequestId";
 | 
			
		||||
        private readonly Random _random;
 | 
			
		||||
        private IWebHostBuilder _webHostBuilder;
 | 
			
		||||
@@ -428,55 +422,6 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
            header.First().ShouldBe(value);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void ThenTheResponseBodyHeaderIs(string key, string value)
 | 
			
		||||
        {
 | 
			
		||||
            var header = _response.Content.Headers.GetValues(key);
 | 
			
		||||
            header.First().ShouldBe(value);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void ThenTheTraceHeaderIsSet(string key)
 | 
			
		||||
        {
 | 
			
		||||
            var header = _response.Headers.GetValues(key);
 | 
			
		||||
            header.First().ShouldNotBeNullOrEmpty();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void GivenOcelotIsRunningUsingJsonSerializedCache()
 | 
			
		||||
        {
 | 
			
		||||
            _webHostBuilder = new WebHostBuilder();
 | 
			
		||||
 | 
			
		||||
            _webHostBuilder
 | 
			
		||||
                .ConfigureAppConfiguration((hostingContext, config) =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
 | 
			
		||||
                    var env = hostingContext.HostingEnvironment;
 | 
			
		||||
                    config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: false)
 | 
			
		||||
                        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: false);
 | 
			
		||||
                    config.AddJsonFile("ocelot.json", false, false);
 | 
			
		||||
                    config.AddEnvironmentVariables();
 | 
			
		||||
                })
 | 
			
		||||
                .ConfigureServices(s =>
 | 
			
		||||
                {
 | 
			
		||||
                    s.AddOcelot()
 | 
			
		||||
                        .AddCacheManager((x) =>
 | 
			
		||||
                        {
 | 
			
		||||
                            x.WithMicrosoftLogging(log =>
 | 
			
		||||
                                {
 | 
			
		||||
                                    log.AddConsole(LogLevel.Debug);
 | 
			
		||||
                                })
 | 
			
		||||
                                .WithJsonSerializer()
 | 
			
		||||
                                .WithHandle(typeof(InMemoryJsonHandle<>));
 | 
			
		||||
                        });
 | 
			
		||||
                })
 | 
			
		||||
                .Configure(app =>
 | 
			
		||||
                {
 | 
			
		||||
                    app.UseOcelot().Wait();
 | 
			
		||||
                }); 
 | 
			
		||||
 | 
			
		||||
            _ocelotServer = new TestServer(_webHostBuilder);
 | 
			
		||||
 | 
			
		||||
            _ocelotClient = _ocelotServer.CreateClient();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void GivenOcelotIsRunningUsingConsulToStoreConfig()
 | 
			
		||||
        {
 | 
			
		||||
            _webHostBuilder = new WebHostBuilder();
 | 
			
		||||
@@ -505,69 +450,6 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
            _ocelotClient = _ocelotServer.CreateClient();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void GivenOcelotIsRunningUsingConsulToStoreConfigAndJsonSerializedCache()
 | 
			
		||||
        {
 | 
			
		||||
            _webHostBuilder = new WebHostBuilder();
 | 
			
		||||
 | 
			
		||||
            _webHostBuilder
 | 
			
		||||
                .ConfigureAppConfiguration((hostingContext, config) =>
 | 
			
		||||
                {
 | 
			
		||||
                    config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
 | 
			
		||||
                    var env = hostingContext.HostingEnvironment;
 | 
			
		||||
                    config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: false)
 | 
			
		||||
                        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: false);
 | 
			
		||||
                    config.AddJsonFile("ocelot.json", optional: true, reloadOnChange: false);
 | 
			
		||||
                    config.AddEnvironmentVariables();
 | 
			
		||||
                })
 | 
			
		||||
                .ConfigureServices(s =>
 | 
			
		||||
                {
 | 
			
		||||
                    s.AddOcelot()
 | 
			
		||||
                        .AddCacheManager((x) =>
 | 
			
		||||
                        {
 | 
			
		||||
                            x.WithMicrosoftLogging(log =>
 | 
			
		||||
                                {
 | 
			
		||||
                                    log.AddConsole(LogLevel.Debug);
 | 
			
		||||
                                })
 | 
			
		||||
                                .WithJsonSerializer()
 | 
			
		||||
                                .WithHandle(typeof(InMemoryJsonHandle<>));
 | 
			
		||||
                        })
 | 
			
		||||
                        .AddStoreOcelotConfigurationInConsul();
 | 
			
		||||
                })
 | 
			
		||||
                .Configure(app =>
 | 
			
		||||
                {
 | 
			
		||||
                    app.UseOcelot().Wait();
 | 
			
		||||
                }); 
 | 
			
		||||
 | 
			
		||||
            _ocelotServer = new TestServer(_webHostBuilder);
 | 
			
		||||
 | 
			
		||||
            _ocelotClient = _ocelotServer.CreateClient();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        internal void ThenTheResponseShouldBe(FileConfiguration expecteds)
 | 
			
		||||
        {
 | 
			
		||||
            var response = JsonConvert.DeserializeObject<FileConfiguration>(_response.Content.ReadAsStringAsync().Result);
 | 
			
		||||
 | 
			
		||||
            response.GlobalConfiguration.RequestIdKey.ShouldBe(expecteds.GlobalConfiguration.RequestIdKey);
 | 
			
		||||
            response.GlobalConfiguration.ServiceDiscoveryProvider.Host.ShouldBe(expecteds.GlobalConfiguration.ServiceDiscoveryProvider.Host);
 | 
			
		||||
            response.GlobalConfiguration.ServiceDiscoveryProvider.Port.ShouldBe(expecteds.GlobalConfiguration.ServiceDiscoveryProvider.Port);
 | 
			
		||||
 | 
			
		||||
            for (var i = 0; i < response.ReRoutes.Count; i++)
 | 
			
		||||
            {
 | 
			
		||||
                for (var j = 0; j < response.ReRoutes[i].DownstreamHostAndPorts.Count; j++)
 | 
			
		||||
                {
 | 
			
		||||
                    var result = response.ReRoutes[i].DownstreamHostAndPorts[j];
 | 
			
		||||
                    var expected = expecteds.ReRoutes[i].DownstreamHostAndPorts[j];
 | 
			
		||||
                    result.Host.ShouldBe(expected.Host);
 | 
			
		||||
                    result.Port.ShouldBe(expected.Port);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                response.ReRoutes[i].DownstreamPathTemplate.ShouldBe(expecteds.ReRoutes[i].DownstreamPathTemplate);
 | 
			
		||||
                response.ReRoutes[i].DownstreamScheme.ShouldBe(expecteds.ReRoutes[i].DownstreamScheme);
 | 
			
		||||
                response.ReRoutes[i].UpstreamPathTemplate.ShouldBe(expecteds.ReRoutes[i].UpstreamPathTemplate);
 | 
			
		||||
                response.ReRoutes[i].UpstreamHttpMethod.ShouldBe(expecteds.ReRoutes[i].UpstreamHttpMethod);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// This is annoying cos it should be in the constructor but we need to set up the file before calling startup so its a step.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
@@ -590,15 +472,6 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
                .UseConfiguration(configuration)
 | 
			
		||||
                .ConfigureServices(s =>
 | 
			
		||||
                {
 | 
			
		||||
                    Action<ConfigurationBuilderCachePart> settings = (x) =>
 | 
			
		||||
                    {
 | 
			
		||||
                        x.WithMicrosoftLogging(log =>
 | 
			
		||||
                        {
 | 
			
		||||
                            log.AddConsole(LogLevel.Debug);
 | 
			
		||||
                        })
 | 
			
		||||
                        .WithDictionaryHandle();
 | 
			
		||||
                    };
 | 
			
		||||
 | 
			
		||||
                    s.AddOcelot(configuration);
 | 
			
		||||
                })
 | 
			
		||||
                .ConfigureLogging(l =>
 | 
			
		||||
@@ -688,26 +561,6 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void GivenIHaveAnOcelotToken(string adminPath)
 | 
			
		||||
        {
 | 
			
		||||
            var tokenUrl = $"{adminPath}/connect/token";
 | 
			
		||||
            var formData = new List<KeyValuePair<string, string>>
 | 
			
		||||
            {
 | 
			
		||||
                new KeyValuePair<string, string>("client_id", "admin"),
 | 
			
		||||
                new KeyValuePair<string, string>("client_secret", "secret"),
 | 
			
		||||
                new KeyValuePair<string, string>("scope", "admin"),
 | 
			
		||||
                new KeyValuePair<string, string>("username", "admin"),
 | 
			
		||||
                new KeyValuePair<string, string>("password", "admin"),
 | 
			
		||||
                new KeyValuePair<string, string>("grant_type", "password")
 | 
			
		||||
            };
 | 
			
		||||
            var content = new FormUrlEncodedContent(formData);
 | 
			
		||||
 | 
			
		||||
            var response = _ocelotClient.PostAsync(tokenUrl, content).Result;
 | 
			
		||||
            var responseContent = response.Content.ReadAsStringAsync().Result;
 | 
			
		||||
            response.EnsureSuccessStatusCode();
 | 
			
		||||
            _token = JsonConvert.DeserializeObject<BearerToken>(responseContent);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void VerifyIdentiryServerStarted(string url)
 | 
			
		||||
        {
 | 
			
		||||
            using (var httpClient = new HttpClient())
 | 
			
		||||
@@ -883,11 +736,6 @@ namespace Ocelot.AcceptanceTests
 | 
			
		||||
            _response.Headers.GetValues(RequestIdKey).First().ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void ThenTheContentLengthIs(int expected)
 | 
			
		||||
        {
 | 
			
		||||
            _response.Content.Headers.ContentLength.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void WhenIMakeLotsOfDifferentRequestsToTheApiGateway()
 | 
			
		||||
        {
 | 
			
		||||
            int numberOfRequests = 100;
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,6 @@ using System.Net;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using System.Net.Http.Headers;
 | 
			
		||||
using System.Security.Claims;
 | 
			
		||||
using CacheManager.Core;
 | 
			
		||||
using IdentityServer4.AccessTokenValidation;
 | 
			
		||||
using IdentityServer4.Models;
 | 
			
		||||
using IdentityServer4.Test;
 | 
			
		||||
@@ -557,17 +556,7 @@ namespace Ocelot.IntegrationTests
 | 
			
		||||
               })
 | 
			
		||||
               .ConfigureServices(x =>
 | 
			
		||||
               {
 | 
			
		||||
                   Action<ConfigurationBuilderCachePart> settings = (s) =>
 | 
			
		||||
                   {
 | 
			
		||||
                       s.WithMicrosoftLogging(log =>
 | 
			
		||||
                       {
 | 
			
		||||
                           log.AddConsole(LogLevel.Debug);
 | 
			
		||||
                       })
 | 
			
		||||
                           .WithDictionaryHandle();
 | 
			
		||||
                   };
 | 
			
		||||
 | 
			
		||||
                   x.AddOcelot()
 | 
			
		||||
                       .AddCacheManager(settings)
 | 
			
		||||
                       .AddAdministration("/administration", "secret");
 | 
			
		||||
               })
 | 
			
		||||
               .Configure(app =>
 | 
			
		||||
@@ -682,10 +671,6 @@ namespace Ocelot.IntegrationTests
 | 
			
		||||
                .ConfigureServices(x => {
 | 
			
		||||
                    x.AddSingleton(_webHostBuilder);
 | 
			
		||||
                    x.AddOcelot()
 | 
			
		||||
                    .AddCacheManager(c =>
 | 
			
		||||
                    {
 | 
			
		||||
                        c.WithDictionaryHandle();
 | 
			
		||||
                    })
 | 
			
		||||
                    .AddAdministration("/administration", configOptions);
 | 
			
		||||
                    })
 | 
			
		||||
                    .Configure(app => {
 | 
			
		||||
@@ -714,17 +699,7 @@ namespace Ocelot.IntegrationTests
 | 
			
		||||
                })
 | 
			
		||||
                .ConfigureServices(x =>
 | 
			
		||||
                {
 | 
			
		||||
                    Action<ConfigurationBuilderCachePart> settings = (s) =>
 | 
			
		||||
                    {
 | 
			
		||||
                        s.WithMicrosoftLogging(log =>
 | 
			
		||||
                            {
 | 
			
		||||
                                log.AddConsole(LogLevel.Debug);
 | 
			
		||||
                            })
 | 
			
		||||
                            .WithDictionaryHandle();
 | 
			
		||||
                    };
 | 
			
		||||
 | 
			
		||||
                    x.AddOcelot()
 | 
			
		||||
                        .AddCacheManager(settings)
 | 
			
		||||
                        .AddAdministration("/administration", "secret");
 | 
			
		||||
                })
 | 
			
		||||
                .Configure(app =>
 | 
			
		||||
@@ -755,10 +730,6 @@ namespace Ocelot.IntegrationTests
 | 
			
		||||
                .ConfigureServices(x => {
 | 
			
		||||
                    x.AddSingleton(_webHostBuilder);
 | 
			
		||||
                    x.AddOcelot()
 | 
			
		||||
                        .AddCacheManager(c =>
 | 
			
		||||
                        {
 | 
			
		||||
                            c.WithDictionaryHandle();
 | 
			
		||||
                        })
 | 
			
		||||
                        .AddAdministration("/administration", "secret");
 | 
			
		||||
                })
 | 
			
		||||
                .Configure(app => {
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,6 @@ using System.IO;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using Microsoft.AspNetCore.Builder;
 | 
			
		||||
using Microsoft.AspNetCore.Hosting;
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
using Newtonsoft.Json;
 | 
			
		||||
using Ocelot.Configuration.File;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
@@ -13,7 +12,6 @@ using Xunit;
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using System.Collections.Concurrent;
 | 
			
		||||
using CacheManager.Core;
 | 
			
		||||
using Microsoft.Extensions.Configuration;
 | 
			
		||||
using Microsoft.Extensions.Logging;
 | 
			
		||||
using Ocelot.DependencyInjection;
 | 
			
		||||
@@ -113,17 +111,7 @@ namespace Ocelot.IntegrationTests
 | 
			
		||||
                })
 | 
			
		||||
                .ConfigureServices(x =>
 | 
			
		||||
                {
 | 
			
		||||
                    Action<ConfigurationBuilderCachePart> settings = (s) =>
 | 
			
		||||
                    {
 | 
			
		||||
                        s.WithMicrosoftLogging(log =>
 | 
			
		||||
                            {
 | 
			
		||||
                                log.AddConsole(LogLevel.Debug);
 | 
			
		||||
                            })
 | 
			
		||||
                            .WithDictionaryHandle();
 | 
			
		||||
                    };
 | 
			
		||||
 | 
			
		||||
                    x.AddOcelot()
 | 
			
		||||
                        .AddCacheManager(settings)
 | 
			
		||||
                        .AddAdministration("/administration", "secret");
 | 
			
		||||
                })
 | 
			
		||||
                .Configure(app =>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Middleware;
 | 
			
		||||
using Xunit;
 | 
			
		||||
 | 
			
		||||
[assembly: CollectionBehavior(DisableTestParallelization = true)]
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Authentication
 | 
			
		||||
{
 | 
			
		||||
@@ -15,14 +16,16 @@ namespace Ocelot.UnitTests.Authentication
 | 
			
		||||
    using Shouldly;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
    using Ocelot.Configuration;
 | 
			
		||||
    using Ocelot.Middleware;
 | 
			
		||||
 | 
			
		||||
    public class AuthenticationMiddlewareTests
 | 
			
		||||
    {
 | 
			
		||||
        private AuthenticationMiddleware _middleware;
 | 
			
		||||
        private Mock<IOcelotLoggerFactory> _factory;
 | 
			
		||||
        private readonly Mock<IOcelotLoggerFactory> _factory;
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private OcelotRequestDelegate _next;
 | 
			
		||||
        private DownstreamContext _downstreamContext;
 | 
			
		||||
        private readonly DownstreamContext _downstreamContext;
 | 
			
		||||
 | 
			
		||||
        public AuthenticationMiddlewareTests()
 | 
			
		||||
        {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,103 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
using CacheManager.Core;
 | 
			
		||||
using Moq;
 | 
			
		||||
using Ocelot.Cache;
 | 
			
		||||
using Shouldly;
 | 
			
		||||
using TestStack.BDDfy;
 | 
			
		||||
using Xunit;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.UnitTests.Cache
 | 
			
		||||
{
 | 
			
		||||
    public class CacheManagerCacheTests
 | 
			
		||||
    {
 | 
			
		||||
        private OcelotCacheManagerCache<string> _ocelotOcelotCacheManager;
 | 
			
		||||
        private Mock<ICacheManager<string>> _mockCacheManager;
 | 
			
		||||
        private string _key;
 | 
			
		||||
        private string _value;
 | 
			
		||||
        private string _resultGet;
 | 
			
		||||
        private TimeSpan _ttlSeconds;
 | 
			
		||||
        private string _region;
 | 
			
		||||
 | 
			
		||||
        public CacheManagerCacheTests()
 | 
			
		||||
        {
 | 
			
		||||
            _mockCacheManager = new Mock<ICacheManager<string>>();
 | 
			
		||||
            _ocelotOcelotCacheManager = new OcelotCacheManagerCache<string>(_mockCacheManager.Object);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_get_from_cache()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => x.GivenTheFollowingIsCached("someKey", "someRegion", "someValue"))
 | 
			
		||||
                .When(x => x.WhenIGetFromTheCache())
 | 
			
		||||
                .Then(x => x.ThenTheResultIs("someValue"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_add_to_cache()
 | 
			
		||||
        {
 | 
			
		||||
            this.When(x => x.WhenIAddToTheCache("someKey", "someValue", TimeSpan.FromSeconds(1)))
 | 
			
		||||
                .Then(x => x.ThenTheCacheIsCalledCorrectly())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_delete_key_from_cache()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(_ => GivenTheFollowingRegion("fookey"))
 | 
			
		||||
                .When(_ => WhenIDeleteTheRegion("fookey"))
 | 
			
		||||
                .Then(_ => ThenTheRegionIsDeleted("fookey"))
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIDeleteTheRegion(string region)
 | 
			
		||||
        {
 | 
			
		||||
            _ocelotOcelotCacheManager.ClearRegion(region);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheRegionIsDeleted(string region)
 | 
			
		||||
        {
 | 
			
		||||
            _mockCacheManager
 | 
			
		||||
                .Verify(x => x.ClearRegion(region), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheFollowingRegion(string key)
 | 
			
		||||
        {
 | 
			
		||||
            _ocelotOcelotCacheManager.Add(key, "doesnt matter", TimeSpan.FromSeconds(10), "region");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIAddToTheCache(string key, string value, TimeSpan ttlSeconds)
 | 
			
		||||
        {
 | 
			
		||||
            _key = key;
 | 
			
		||||
            _value = value;
 | 
			
		||||
            _ttlSeconds = ttlSeconds;
 | 
			
		||||
            _ocelotOcelotCacheManager.Add(_key, _value, _ttlSeconds, "region");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheCacheIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _mockCacheManager
 | 
			
		||||
                .Verify(x => x.Add(It.IsAny<CacheItem<string>>()), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheResultIs(string expected)
 | 
			
		||||
        {
 | 
			
		||||
            _resultGet.ShouldBe(expected);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIGetFromTheCache()
 | 
			
		||||
        {
 | 
			
		||||
            _resultGet = _ocelotOcelotCacheManager.Get(_key, _region);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheFollowingIsCached(string key, string region, string value)
 | 
			
		||||
        {
 | 
			
		||||
            _key = key;
 | 
			
		||||
            _value = value;
 | 
			
		||||
            _region = region;
 | 
			
		||||
            _mockCacheManager
 | 
			
		||||
                .Setup(x => x.Get<string>(It.IsAny<string>(), It.IsAny<string>()))
 | 
			
		||||
                .Returns(value);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,95 +0,0 @@
 | 
			
		||||
namespace Ocelot.UnitTests.Cache
 | 
			
		||||
{
 | 
			
		||||
    using System.Linq;
 | 
			
		||||
    using System.Net;
 | 
			
		||||
    using System.Net.Http.Headers;
 | 
			
		||||
    using CacheManager.Core;
 | 
			
		||||
    using Shouldly;
 | 
			
		||||
    using System.Collections.Generic;
 | 
			
		||||
    using System.Net.Http;
 | 
			
		||||
    using System.Threading.Tasks;
 | 
			
		||||
    using Moq;
 | 
			
		||||
    using Ocelot.Cache;
 | 
			
		||||
    using Ocelot.Cache.Middleware;
 | 
			
		||||
    using Ocelot.Configuration;
 | 
			
		||||
    using Ocelot.Configuration.Builder;
 | 
			
		||||
    using Ocelot.Logging;
 | 
			
		||||
    using Ocelot.Middleware;
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
    using Microsoft.AspNetCore.Http;
 | 
			
		||||
    using Ocelot.Middleware.Multiplexer;
 | 
			
		||||
 | 
			
		||||
    public class OutputCacheMiddlewareRealCacheTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly IOcelotCache<CachedResponse> _cacheManager;
 | 
			
		||||
        private readonly OutputCacheMiddleware _middleware;
 | 
			
		||||
        private readonly DownstreamContext _downstreamContext;
 | 
			
		||||
        private OcelotRequestDelegate _next;
 | 
			
		||||
        private Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
			
		||||
        private IRegionCreator _regionCreator;
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
 | 
			
		||||
        public OutputCacheMiddlewareRealCacheTests()
 | 
			
		||||
        {
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
            _loggerFactory.Setup(x => x.CreateLogger<OutputCacheMiddleware>()).Returns(_logger.Object);
 | 
			
		||||
            _regionCreator = new RegionCreator();
 | 
			
		||||
            var cacheManagerOutputCache = CacheFactory.Build<CachedResponse>("OcelotOutputCache", x =>
 | 
			
		||||
            {
 | 
			
		||||
                x.WithDictionaryHandle();
 | 
			
		||||
            });
 | 
			
		||||
            _cacheManager = new OcelotCacheManagerCache<CachedResponse>(cacheManagerOutputCache);
 | 
			
		||||
            _downstreamContext = new DownstreamContext(new DefaultHttpContext());
 | 
			
		||||
            _downstreamContext.DownstreamRequest = new Ocelot.Request.Middleware.DownstreamRequest(new HttpRequestMessage(HttpMethod.Get, "https://some.url/blah?abcd=123"));
 | 
			
		||||
            _next = context => Task.CompletedTask;
 | 
			
		||||
            _middleware = new OutputCacheMiddleware(_next, _loggerFactory.Object, _cacheManager, _regionCreator);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_cache_content_headers()
 | 
			
		||||
        {
 | 
			
		||||
            var content = new StringContent("{\"Test\": 1}")
 | 
			
		||||
            {
 | 
			
		||||
                Headers = { ContentType = new MediaTypeHeaderValue("application/json")}
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            var response = new DownstreamResponse(content, HttpStatusCode.OK, new List<KeyValuePair<string, IEnumerable<string>>>());
 | 
			
		||||
 | 
			
		||||
            this.Given(x => x.GivenResponseIsNotCached(response))
 | 
			
		||||
                .And(x => x.GivenTheDownstreamRouteIs())
 | 
			
		||||
                .When(x => x.WhenICallTheMiddleware())
 | 
			
		||||
                .Then(x => x.ThenTheContentTypeHeaderIsCached())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddleware()
 | 
			
		||||
        {
 | 
			
		||||
            _middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheContentTypeHeaderIsCached()
 | 
			
		||||
        {
 | 
			
		||||
            var result = _cacheManager.Get("GET-https://some.url/blah?abcd=123", "kanken");
 | 
			
		||||
            var header = result.ContentHeaders["Content-Type"];
 | 
			
		||||
            header.First().ShouldBe("application/json");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenResponseIsNotCached(DownstreamResponse response)
 | 
			
		||||
        {
 | 
			
		||||
            _downstreamContext.DownstreamResponse = response;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDownstreamRouteIs()
 | 
			
		||||
        {
 | 
			
		||||
            var reRoute = new DownstreamReRouteBuilder()
 | 
			
		||||
                .WithIsCached(true)
 | 
			
		||||
                .WithCacheOptions(new CacheOptions(100, "kanken"))
 | 
			
		||||
                .WithUpstreamHttpMethod(new List<string> { "Get" })
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            _downstreamContext.DownstreamReRoute = reRoute;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -16,24 +16,22 @@
 | 
			
		||||
    using TestStack.BDDfy;
 | 
			
		||||
    using Xunit;
 | 
			
		||||
    using System.Net;
 | 
			
		||||
    using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
    using Ocelot.Middleware;
 | 
			
		||||
    using Ocelot.Middleware.Multiplexer;
 | 
			
		||||
 | 
			
		||||
    public class OutputCacheMiddlewareTests
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Mock<IOcelotCache<CachedResponse>> _cacheManager;    
 | 
			
		||||
        private readonly Mock<IOcelotCache<CachedResponse>> _cache;    
 | 
			
		||||
        private readonly Mock<IOcelotLoggerFactory> _loggerFactory;
 | 
			
		||||
        private Mock<IOcelotLogger> _logger;
 | 
			
		||||
        private OutputCacheMiddleware _middleware;
 | 
			
		||||
        private readonly DownstreamContext _downstreamContext;
 | 
			
		||||
        private readonly OcelotRequestDelegate _next;
 | 
			
		||||
        private CachedResponse _response;
 | 
			
		||||
        private readonly IRegionCreator _regionCreator;
 | 
			
		||||
 | 
			
		||||
        public OutputCacheMiddlewareTests()
 | 
			
		||||
        {
 | 
			
		||||
            _cacheManager = new Mock<IOcelotCache<CachedResponse>>();
 | 
			
		||||
            _regionCreator = new RegionCreator();
 | 
			
		||||
            _cache = new Mock<IOcelotCache<CachedResponse>>();
 | 
			
		||||
            _downstreamContext = new DownstreamContext(new DefaultHttpContext());
 | 
			
		||||
            _loggerFactory = new Mock<IOcelotLoggerFactory>();
 | 
			
		||||
            _logger = new Mock<IOcelotLogger>();
 | 
			
		||||
@@ -91,14 +89,14 @@
 | 
			
		||||
 | 
			
		||||
        private void WhenICallTheMiddleware()
 | 
			
		||||
        {
 | 
			
		||||
            _middleware = new OutputCacheMiddleware(_next, _loggerFactory.Object, _cacheManager.Object, _regionCreator);
 | 
			
		||||
            _middleware = new OutputCacheMiddleware(_next, _loggerFactory.Object, _cache.Object);
 | 
			
		||||
            _middleware.Invoke(_downstreamContext).GetAwaiter().GetResult();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void GivenThereIsACachedResponse(CachedResponse response)
 | 
			
		||||
        {
 | 
			
		||||
            _response = response;
 | 
			
		||||
            _cacheManager
 | 
			
		||||
            _cache
 | 
			
		||||
              .Setup(x => x.Get(It.IsAny<string>(), It.IsAny<string>()))
 | 
			
		||||
              .Returns(_response);
 | 
			
		||||
        }
 | 
			
		||||
@@ -127,13 +125,13 @@
 | 
			
		||||
 | 
			
		||||
        private void ThenTheCacheGetIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _cacheManager
 | 
			
		||||
            _cache
 | 
			
		||||
                .Verify(x => x.Get(It.IsAny<string>(), It.IsAny<string>()), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void ThenTheCacheAddIsCalledCorrectly()
 | 
			
		||||
        {
 | 
			
		||||
            _cacheManager
 | 
			
		||||
            _cache
 | 
			
		||||
                .Verify(x => x.Add(It.IsAny<string>(), It.IsAny<CachedResponse>(), It.IsAny<TimeSpan>(), It.IsAny<string>()), Times.Once);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,6 @@ using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using CacheManager.Core;
 | 
			
		||||
using Microsoft.AspNetCore.Hosting;
 | 
			
		||||
using Microsoft.AspNetCore.Hosting.Internal;
 | 
			
		||||
using Microsoft.Extensions.Configuration;
 | 
			
		||||
@@ -81,16 +80,6 @@ namespace Ocelot.UnitTests.DependencyInjection
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_set_up_cache_manager()
 | 
			
		||||
        {
 | 
			
		||||
            this.Given(x => WhenISetUpOcelotServices())
 | 
			
		||||
                .When(x => WhenISetUpCacheManager())
 | 
			
		||||
                .Then(x => ThenAnExceptionIsntThrown())
 | 
			
		||||
                .And(x => OnlyOneVersionOfEachCacheIsRegistered())
 | 
			
		||||
                .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Fact]
 | 
			
		||||
        public void should_set_up_consul()
 | 
			
		||||
        {            
 | 
			
		||||
@@ -282,24 +271,6 @@ namespace Ocelot.UnitTests.DependencyInjection
 | 
			
		||||
            first.ShouldBe(second);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void OnlyOneVersionOfEachCacheIsRegistered()
 | 
			
		||||
        {
 | 
			
		||||
            var outputCache = _services.Single(x => x.ServiceType == typeof(IOcelotCache<CachedResponse>));
 | 
			
		||||
            var outputCacheManager = _services.Single(x => x.ServiceType == typeof(ICacheManager<CachedResponse>));
 | 
			
		||||
            var instance = (ICacheManager<CachedResponse>)outputCacheManager.ImplementationInstance;
 | 
			
		||||
            var ocelotConfigCache = _services.Single(x => x.ServiceType == typeof(IOcelotCache<IInternalConfiguration>));
 | 
			
		||||
            var ocelotConfigCacheManager = _services.Single(x => x.ServiceType == typeof(ICacheManager<IInternalConfiguration>));
 | 
			
		||||
            var fileConfigCache = _services.Single(x => x.ServiceType == typeof(IOcelotCache<FileConfiguration>));
 | 
			
		||||
            var fileConfigCacheManager = _services.Single(x => x.ServiceType == typeof(ICacheManager<FileConfiguration>));
 | 
			
		||||
 | 
			
		||||
            instance.Configuration.MaxRetries.ShouldBe(_maxRetries);
 | 
			
		||||
            outputCache.ShouldNotBeNull();
 | 
			
		||||
            ocelotConfigCache.ShouldNotBeNull();
 | 
			
		||||
            ocelotConfigCacheManager.ShouldNotBeNull();
 | 
			
		||||
            fileConfigCache.ShouldNotBeNull();
 | 
			
		||||
            fileConfigCacheManager.ShouldNotBeNull();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenISetUpConsul()
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
@@ -365,21 +336,6 @@ namespace Ocelot.UnitTests.DependencyInjection
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenISetUpCacheManager()
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                _ocelotBuilder.AddCacheManager(x => {
 | 
			
		||||
                    x.WithMaxRetries(_maxRetries);
 | 
			
		||||
                    x.WithDictionaryHandle();
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception e)
 | 
			
		||||
            {
 | 
			
		||||
                _ex = e;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void WhenIAccessLoggerFactory()
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,9 @@
 | 
			
		||||
namespace Ocelot.UnitTests.Middleware
 | 
			
		||||
{
 | 
			
		||||
    using System;
 | 
			
		||||
    using Microsoft.Extensions.Configuration;
 | 
			
		||||
    using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
    using Ocelot.Cache;
 | 
			
		||||
    using Ocelot.DependencyInjection;
 | 
			
		||||
    using Ocelot.DownstreamRouteFinder.Middleware;
 | 
			
		||||
    using Ocelot.DownstreamUrlCreator.Middleware;
 | 
			
		||||
@@ -40,7 +42,6 @@ namespace Ocelot.UnitTests.Middleware
 | 
			
		||||
                 .BDDfy();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        private void ThenThePipelineIsBuilt()
 | 
			
		||||
        {
 | 
			
		||||
            _handlers.ShouldNotBeNull();
 | 
			
		||||
@@ -67,7 +68,6 @@ namespace Ocelot.UnitTests.Middleware
 | 
			
		||||
            _handlers = _builder.BuildOcelotPipeline(new OcelotPipelineConfiguration());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        private void GivenTheDepedenciesAreSetUp()
 | 
			
		||||
        {
 | 
			
		||||
            IConfigurationBuilder test = new ConfigurationBuilder();
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user