only get config once in a request...could make this its own middleware one day?

This commit is contained in:
Tom Gardham-Pallister
2017-11-10 18:07:08 +00:00
parent 1d61e403ed
commit 88e51971c5
8 changed files with 61 additions and 31 deletions

View File

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Ocelot.Configuration;
using Ocelot.Configuration.Provider; using Ocelot.Configuration.Provider;
using Ocelot.DownstreamRouteFinder.UrlMatcher; using Ocelot.DownstreamRouteFinder.UrlMatcher;
using Ocelot.Errors; using Ocelot.Errors;
@ -12,24 +13,20 @@ namespace Ocelot.DownstreamRouteFinder.Finder
{ {
public class DownstreamRouteFinder : IDownstreamRouteFinder public class DownstreamRouteFinder : IDownstreamRouteFinder
{ {
private readonly IOcelotConfigurationProvider _configProvider;
private readonly IUrlPathToUrlTemplateMatcher _urlMatcher; private readonly IUrlPathToUrlTemplateMatcher _urlMatcher;
private readonly IUrlPathPlaceholderNameAndValueFinder _urlPathPlaceholderNameAndValueFinder; private readonly IUrlPathPlaceholderNameAndValueFinder _urlPathPlaceholderNameAndValueFinder;
public DownstreamRouteFinder(IOcelotConfigurationProvider configProvider, IUrlPathToUrlTemplateMatcher urlMatcher, IUrlPathPlaceholderNameAndValueFinder urlPathPlaceholderNameAndValueFinder) public DownstreamRouteFinder(IUrlPathToUrlTemplateMatcher urlMatcher, IUrlPathPlaceholderNameAndValueFinder urlPathPlaceholderNameAndValueFinder)
{ {
_configProvider = configProvider;
_urlMatcher = urlMatcher; _urlMatcher = urlMatcher;
_urlPathPlaceholderNameAndValueFinder = urlPathPlaceholderNameAndValueFinder; _urlPathPlaceholderNameAndValueFinder = urlPathPlaceholderNameAndValueFinder;
} }
public async Task<Response<DownstreamRoute>> FindDownstreamRoute(string upstreamUrlPath, string upstreamHttpMethod) public Response<DownstreamRoute> FindDownstreamRoute(string upstreamUrlPath, string upstreamHttpMethod, IOcelotConfiguration configuration)
{ {
upstreamUrlPath = upstreamUrlPath.SetLastCharacterAs('/'); upstreamUrlPath = upstreamUrlPath.SetLastCharacterAs('/');
var configuration = await _configProvider.Get(); var applicableReRoutes = configuration.ReRoutes.Where(r => r.UpstreamHttpMethod.Count == 0 || r.UpstreamHttpMethod.Select(x => x.Method.ToLower()).Contains(upstreamHttpMethod.ToLower()));
var applicableReRoutes = configuration.Data.ReRoutes.Where(r => r.UpstreamHttpMethod.Count == 0 || r.UpstreamHttpMethod.Select(x => x.Method.ToLower()).Contains(upstreamHttpMethod.ToLower()));
foreach (var reRoute in applicableReRoutes) foreach (var reRoute in applicableReRoutes)
{ {

View File

@ -1,10 +1,11 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using Ocelot.Configuration;
using Ocelot.Responses; using Ocelot.Responses;
namespace Ocelot.DownstreamRouteFinder.Finder namespace Ocelot.DownstreamRouteFinder.Finder
{ {
public interface IDownstreamRouteFinder public interface IDownstreamRouteFinder
{ {
Task<Response<DownstreamRoute>> FindDownstreamRoute(string upstreamUrlPath, string upstreamHttpMethod); Response<DownstreamRoute> FindDownstreamRoute(string upstreamUrlPath, string upstreamHttpMethod, IOcelotConfiguration configuration);
} }
} }

View File

@ -2,6 +2,7 @@ using System.Linq;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Ocelot.Configuration.Provider;
using Ocelot.DownstreamRouteFinder.Finder; using Ocelot.DownstreamRouteFinder.Finder;
using Ocelot.Infrastructure.Extensions; using Ocelot.Infrastructure.Extensions;
using Ocelot.Infrastructure.RequestData; using Ocelot.Infrastructure.RequestData;
@ -16,13 +17,17 @@ namespace Ocelot.DownstreamRouteFinder.Middleware
private readonly RequestDelegate _next; private readonly RequestDelegate _next;
private readonly IDownstreamRouteFinder _downstreamRouteFinder; private readonly IDownstreamRouteFinder _downstreamRouteFinder;
private readonly IOcelotLogger _logger; private readonly IOcelotLogger _logger;
private readonly IOcelotConfigurationProvider _configProvider;
public DownstreamRouteFinderMiddleware(RequestDelegate next, public DownstreamRouteFinderMiddleware(RequestDelegate next,
IOcelotLoggerFactory loggerFactory, IOcelotLoggerFactory loggerFactory,
IDownstreamRouteFinder downstreamRouteFinder, IDownstreamRouteFinder downstreamRouteFinder,
IRequestScopedDataRepository requestScopedDataRepository) IRequestScopedDataRepository requestScopedDataRepository,
IOcelotConfigurationProvider configProvider)
:base(requestScopedDataRepository) :base(requestScopedDataRepository)
{ {
_configProvider = configProvider;
_next = next; _next = next;
_downstreamRouteFinder = downstreamRouteFinder; _downstreamRouteFinder = downstreamRouteFinder;
_logger = loggerFactory.CreateLogger<DownstreamRouteFinderMiddleware>(); _logger = loggerFactory.CreateLogger<DownstreamRouteFinderMiddleware>();
@ -32,9 +37,19 @@ namespace Ocelot.DownstreamRouteFinder.Middleware
{ {
var upstreamUrlPath = context.Request.Path.ToString(); var upstreamUrlPath = context.Request.Path.ToString();
//todo make this getting config its own middleware one day?
var configuration = await _configProvider.Get();
if(configuration.IsError)
{
_logger.LogError($"{MiddlewareName} setting pipeline errors. IOcelotConfigurationProvider returned {configuration.Errors.ToErrorString()}");
SetPipelineError(configuration.Errors);
}
SetServiceProviderConfigurationForThisRequest(configuration.Data.ServiceProviderConfiguration);
_logger.LogDebug("upstream url path is {upstreamUrlPath}", upstreamUrlPath); _logger.LogDebug("upstream url path is {upstreamUrlPath}", upstreamUrlPath);
var downstreamRoute = await _downstreamRouteFinder.FindDownstreamRoute(upstreamUrlPath, context.Request.Method); var downstreamRoute = _downstreamRouteFinder.FindDownstreamRoute(upstreamUrlPath, context.Request.Method, configuration.Data);
if (downstreamRoute.IsError) if (downstreamRoute.IsError)
{ {

View File

@ -12,7 +12,6 @@ namespace Ocelot.LoadBalancer.Middleware
{ {
public class LoadBalancingMiddleware : OcelotMiddleware public class LoadBalancingMiddleware : OcelotMiddleware
{ {
private readonly IOcelotConfigurationProvider _configProvider;
private readonly RequestDelegate _next; private readonly RequestDelegate _next;
private readonly IOcelotLogger _logger; private readonly IOcelotLogger _logger;
private readonly ILoadBalancerHouse _loadBalancerHouse; private readonly ILoadBalancerHouse _loadBalancerHouse;
@ -20,11 +19,9 @@ namespace Ocelot.LoadBalancer.Middleware
public LoadBalancingMiddleware(RequestDelegate next, public LoadBalancingMiddleware(RequestDelegate next,
IOcelotLoggerFactory loggerFactory, IOcelotLoggerFactory loggerFactory,
IRequestScopedDataRepository requestScopedDataRepository, IRequestScopedDataRepository requestScopedDataRepository,
ILoadBalancerHouse loadBalancerHouse, ILoadBalancerHouse loadBalancerHouse)
IOcelotConfigurationProvider configProvider)
: base(requestScopedDataRepository) : base(requestScopedDataRepository)
{ {
_configProvider = configProvider;
_next = next; _next = next;
_logger = loggerFactory.CreateLogger<QueryStringBuilderMiddleware>(); _logger = loggerFactory.CreateLogger<QueryStringBuilderMiddleware>();
_loadBalancerHouse = loadBalancerHouse; _loadBalancerHouse = loadBalancerHouse;
@ -32,9 +29,7 @@ namespace Ocelot.LoadBalancer.Middleware
public async Task Invoke(HttpContext context) public async Task Invoke(HttpContext context)
{ {
var configuration = await _configProvider.Get(); var loadBalancer = await _loadBalancerHouse.Get(DownstreamRoute.ReRoute, ServiceProviderConfiguration);
var loadBalancer = await _loadBalancerHouse.Get(DownstreamRoute.ReRoute, configuration.Data.ServiceProviderConfiguration);
if(loadBalancer.IsError) if(loadBalancer.IsError)
{ {
_logger.LogDebug("there was an error retriving the loadbalancer, setting pipeline error"); _logger.LogDebug("there was an error retriving the loadbalancer, setting pipeline error");

View File

@ -1,5 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Net.Http; using System.Net.Http;
using Ocelot.Configuration;
using Ocelot.DownstreamRouteFinder; using Ocelot.DownstreamRouteFinder;
using Ocelot.Errors; using Ocelot.Errors;
using Ocelot.Infrastructure.RequestData; using Ocelot.Infrastructure.RequestData;
@ -30,11 +31,18 @@ namespace Ocelot.Middleware
public HttpResponseMessage HttpResponseMessage => _requestScopedDataRepository.Get<HttpResponseMessage>("HttpResponseMessage").Data; public HttpResponseMessage HttpResponseMessage => _requestScopedDataRepository.Get<HttpResponseMessage>("HttpResponseMessage").Data;
public ServiceProviderConfiguration ServiceProviderConfiguration => _requestScopedDataRepository.Get<ServiceProviderConfiguration>("ServiceProviderConfiguration").Data;
public void SetDownstreamRouteForThisRequest(DownstreamRoute downstreamRoute) public void SetDownstreamRouteForThisRequest(DownstreamRoute downstreamRoute)
{ {
_requestScopedDataRepository.Add("DownstreamRoute", downstreamRoute); _requestScopedDataRepository.Add("DownstreamRoute", downstreamRoute);
} }
public void SetServiceProviderConfigurationForThisRequest(ServiceProviderConfiguration serviceProviderConfiguration)
{
_requestScopedDataRepository.Add("ServiceProviderConfiguration", serviceProviderConfiguration);
}
public void SetUpstreamRequestForThisRequest(Request.Request request) public void SetUpstreamRequestForThisRequest(Request.Request request)
{ {
_requestScopedDataRepository.Add("Request", request); _requestScopedDataRepository.Add("Request", request);

View File

@ -4,7 +4,9 @@
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Moq; using Moq;
using Ocelot.Configuration;
using Ocelot.Configuration.Builder; using Ocelot.Configuration.Builder;
using Ocelot.Configuration.Provider;
using Ocelot.DownstreamRouteFinder; using Ocelot.DownstreamRouteFinder;
using Ocelot.DownstreamRouteFinder.Finder; using Ocelot.DownstreamRouteFinder.Finder;
using Ocelot.DownstreamRouteFinder.Middleware; using Ocelot.DownstreamRouteFinder.Middleware;
@ -17,10 +19,13 @@
public class DownstreamRouteFinderMiddlewareTests : ServerHostedMiddlewareTest public class DownstreamRouteFinderMiddlewareTests : ServerHostedMiddlewareTest
{ {
private readonly Mock<IDownstreamRouteFinder> _downstreamRouteFinder; private readonly Mock<IDownstreamRouteFinder> _downstreamRouteFinder;
private readonly Mock<IOcelotConfigurationProvider> _provider;
private Response<DownstreamRoute> _downstreamRoute; private Response<DownstreamRoute> _downstreamRoute;
private IOcelotConfiguration _config;
public DownstreamRouteFinderMiddlewareTests() public DownstreamRouteFinderMiddlewareTests()
{ {
_provider = new Mock<IOcelotConfigurationProvider>();
_downstreamRouteFinder = new Mock<IDownstreamRouteFinder>(); _downstreamRouteFinder = new Mock<IDownstreamRouteFinder>();
GivenTheTestServerIsConfigured(); GivenTheTestServerIsConfigured();
@ -29,6 +34,8 @@
[Fact] [Fact]
public void should_call_scoped_data_repository_correctly() public void should_call_scoped_data_repository_correctly()
{ {
var config = new OcelotConfiguration(null, null, new ServiceProviderConfigurationBuilder().Build());
this.Given(x => x.GivenTheDownStreamRouteFinderReturns( this.Given(x => x.GivenTheDownStreamRouteFinderReturns(
new DownstreamRoute( new DownstreamRoute(
new List<UrlPathPlaceholderNameAndValue>(), new List<UrlPathPlaceholderNameAndValue>(),
@ -36,16 +43,26 @@
.WithDownstreamPathTemplate("any old string") .WithDownstreamPathTemplate("any old string")
.WithUpstreamHttpMethod(new List<string> { "Get" }) .WithUpstreamHttpMethod(new List<string> { "Get" })
.Build()))) .Build())))
.And(x => GivenTheFollowingConfig(config))
.When(x => x.WhenICallTheMiddleware()) .When(x => x.WhenICallTheMiddleware())
.Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly()) .Then(x => x.ThenTheScopedDataRepositoryIsCalledCorrectly())
.BDDfy(); .BDDfy();
} }
private void GivenTheFollowingConfig(IOcelotConfiguration config)
{
_config = config;
_provider
.Setup(x => x.Get())
.ReturnsAsync(new OkResponse<IOcelotConfiguration>(_config));
}
protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services) protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services)
{ {
services.AddSingleton<IOcelotLoggerFactory, AspDotNetLoggerFactory>(); services.AddSingleton<IOcelotLoggerFactory, AspDotNetLoggerFactory>();
services.AddLogging(); services.AddLogging();
services.AddSingleton(_downstreamRouteFinder.Object); services.AddSingleton(_downstreamRouteFinder.Object);
services.AddSingleton(_provider.Object);
services.AddSingleton(ScopedRepository.Object); services.AddSingleton(ScopedRepository.Object);
} }
@ -58,14 +75,17 @@
{ {
_downstreamRoute = new OkResponse<DownstreamRoute>(downstreamRoute); _downstreamRoute = new OkResponse<DownstreamRoute>(downstreamRoute);
_downstreamRouteFinder _downstreamRouteFinder
.Setup(x => x.FindDownstreamRoute(It.IsAny<string>(), It.IsAny<string>())) .Setup(x => x.FindDownstreamRoute(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<IOcelotConfiguration>()))
.ReturnsAsync(_downstreamRoute); .Returns(_downstreamRoute);
} }
private void ThenTheScopedDataRepositoryIsCalledCorrectly() private void ThenTheScopedDataRepositoryIsCalledCorrectly()
{ {
ScopedRepository ScopedRepository
.Verify(x => x.Add("DownstreamRoute", _downstreamRoute.Data), Times.Once()); .Verify(x => x.Add("DownstreamRoute", _downstreamRoute.Data), Times.Once());
ScopedRepository
.Verify(x => x.Add("ServiceProviderConfiguration", _config.ServiceProviderConfiguration), Times.Once());
} }
} }
} }

View File

@ -16,21 +16,20 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
public class DownstreamRouteFinderTests public class DownstreamRouteFinderTests
{ {
private readonly IDownstreamRouteFinder _downstreamRouteFinder; private readonly IDownstreamRouteFinder _downstreamRouteFinder;
private readonly Mock<IOcelotConfigurationProvider> _mockConfig;
private readonly Mock<IUrlPathToUrlTemplateMatcher> _mockMatcher; private readonly Mock<IUrlPathToUrlTemplateMatcher> _mockMatcher;
private readonly Mock<IUrlPathPlaceholderNameAndValueFinder> _finder; private readonly Mock<IUrlPathPlaceholderNameAndValueFinder> _finder;
private string _upstreamUrlPath; private string _upstreamUrlPath;
private Response<DownstreamRoute> _result; private Response<DownstreamRoute> _result;
private List<ReRoute> _reRoutesConfig; private List<ReRoute> _reRoutesConfig;
private OcelotConfiguration _config;
private Response<UrlMatch> _match; private Response<UrlMatch> _match;
private string _upstreamHttpMethod; private string _upstreamHttpMethod;
public DownstreamRouteFinderTests() public DownstreamRouteFinderTests()
{ {
_mockConfig = new Mock<IOcelotConfigurationProvider>();
_mockMatcher = new Mock<IUrlPathToUrlTemplateMatcher>(); _mockMatcher = new Mock<IUrlPathToUrlTemplateMatcher>();
_finder = new Mock<IUrlPathPlaceholderNameAndValueFinder>(); _finder = new Mock<IUrlPathPlaceholderNameAndValueFinder>();
_downstreamRouteFinder = new Ocelot.DownstreamRouteFinder.Finder.DownstreamRouteFinder(_mockConfig.Object, _mockMatcher.Object, _finder.Object); _downstreamRouteFinder = new Ocelot.DownstreamRouteFinder.Finder.DownstreamRouteFinder(_mockMatcher.Object, _finder.Object);
} }
[Fact] [Fact]
@ -341,9 +340,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
private void GivenTheConfigurationIs(List<ReRoute> reRoutesConfig, string adminPath, ServiceProviderConfiguration serviceProviderConfig) private void GivenTheConfigurationIs(List<ReRoute> reRoutesConfig, string adminPath, ServiceProviderConfiguration serviceProviderConfig)
{ {
_reRoutesConfig = reRoutesConfig; _reRoutesConfig = reRoutesConfig;
_mockConfig _config = new OcelotConfiguration(_reRoutesConfig, adminPath, serviceProviderConfig);
.Setup(x => x.Get())
.ReturnsAsync(new OkResponse<IOcelotConfiguration>(new OcelotConfiguration(_reRoutesConfig, adminPath, serviceProviderConfig)));
} }
private void GivenThereIsAnUpstreamUrlPath(string upstreamUrlPath) private void GivenThereIsAnUpstreamUrlPath(string upstreamUrlPath)
@ -353,7 +350,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
private void WhenICallTheFinder() private void WhenICallTheFinder()
{ {
_result = _downstreamRouteFinder.FindDownstreamRoute(_upstreamUrlPath, _upstreamHttpMethod).Result; _result = _downstreamRouteFinder.FindDownstreamRoute(_upstreamUrlPath, _upstreamHttpMethod, _config);
} }
private void ThenTheFollowingIsReturned(DownstreamRoute expected) private void ThenTheFollowingIsReturned(DownstreamRoute expected)

View File

@ -23,7 +23,6 @@ namespace Ocelot.UnitTests.LoadBalancer
{ {
private readonly Mock<ILoadBalancerHouse> _loadBalancerHouse; private readonly Mock<ILoadBalancerHouse> _loadBalancerHouse;
private readonly Mock<ILoadBalancer> _loadBalancer; private readonly Mock<ILoadBalancer> _loadBalancer;
private readonly Mock<IOcelotConfigurationProvider> _configProvider;
private HostAndPort _hostAndPort; private HostAndPort _hostAndPort;
private OkResponse<DownstreamRoute> _downstreamRoute; private OkResponse<DownstreamRoute> _downstreamRoute;
private ErrorResponse<ILoadBalancer> _getLoadBalancerHouseError; private ErrorResponse<ILoadBalancer> _getLoadBalancerHouseError;
@ -33,7 +32,6 @@ namespace Ocelot.UnitTests.LoadBalancer
public LoadBalancerMiddlewareTests() public LoadBalancerMiddlewareTests()
{ {
_configProvider = new Mock<IOcelotConfigurationProvider>();
_loadBalancerHouse = new Mock<ILoadBalancerHouse>(); _loadBalancerHouse = new Mock<ILoadBalancerHouse>();
_loadBalancer = new Mock<ILoadBalancer>(); _loadBalancer = new Mock<ILoadBalancer>();
_loadBalancerHouse = new Mock<ILoadBalancerHouse>(); _loadBalancerHouse = new Mock<ILoadBalancerHouse>();
@ -111,8 +109,8 @@ namespace Ocelot.UnitTests.LoadBalancer
private void GivenTheConfigurationIs(ServiceProviderConfiguration config) private void GivenTheConfigurationIs(ServiceProviderConfiguration config)
{ {
_config = config; _config = config;
_configProvider ScopedRepository
.Setup(x => x.Get()).ReturnsAsync(new OkResponse<IOcelotConfiguration>(new OcelotConfiguration(null, null, _config))); .Setup(x => x.Get<ServiceProviderConfiguration>("ServiceProviderConfiguration")).Returns(new OkResponse<ServiceProviderConfiguration>(config));
} }
protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services) protected override void GivenTheTestServerServicesAreConfigured(IServiceCollection services)
@ -120,7 +118,6 @@ namespace Ocelot.UnitTests.LoadBalancer
services.AddSingleton<IOcelotLoggerFactory, AspDotNetLoggerFactory>(); services.AddSingleton<IOcelotLoggerFactory, AspDotNetLoggerFactory>();
services.AddLogging(); services.AddLogging();
services.AddSingleton(_loadBalancerHouse.Object); services.AddSingleton(_loadBalancerHouse.Object);
services.AddSingleton(_configProvider.Object);
services.AddSingleton(ScopedRepository.Object); services.AddSingleton(ScopedRepository.Object);
} }