Delegating Handlers from container (#266)

* #259 quickly hacked poc for this together, needs tidying up maybe

* #266 +semver: breaking removed adding delegating handler funcs directly...i feel from container is enough
This commit is contained in:
Tom Pallister
2018-03-09 07:37:37 +00:00
committed by GitHub
parent 28cc519341
commit a31a3ae0fc
21 changed files with 975 additions and 456 deletions

View File

@ -3,16 +3,22 @@ using CacheManager.Core;
using System;
using System.Net.Http;
using IdentityServer4.AccessTokenValidation;
using Ocelot.Requester;
namespace Ocelot.DependencyInjection
{
public interface IOcelotBuilder
{
IOcelotBuilder AddStoreOcelotConfigurationInConsul();
IOcelotBuilder AddCacheManager(Action<ConfigurationBuilderCachePart> settings);
IOcelotBuilder AddOpenTracing(Action<ButterflyOptions> settings);
IOcelotAdministrationBuilder AddAdministration(string path, string secret);
IOcelotAdministrationBuilder AddAdministration(string path, Action<IdentityServerAuthenticationOptions> configOptions);
IOcelotBuilder AddDelegatingHandler(Func<DelegatingHandler> delegatingHandler);
IOcelotBuilder AddDelegatingHandler<T>() where T : DelegatingHandler;
}
}

View File

@ -57,7 +57,6 @@ namespace Ocelot.DependencyInjection
{
private readonly IServiceCollection _services;
private readonly IConfiguration _configurationRoot;
private readonly IDelegatingHandlerHandlerProvider _provider;
public OcelotBuilder(IServiceCollection services, IConfiguration configurationRoot)
{
@ -120,8 +119,7 @@ namespace Ocelot.DependencyInjection
_services.TryAddSingleton<IRequestMapper, RequestMapper>();
_services.TryAddSingleton<IHttpHandlerOptionsCreator, HttpHandlerOptionsCreator>();
_services.TryAddSingleton<IDownstreamAddressesCreator, DownstreamAddressesCreator>();
_services.TryAddSingleton<IDelegatingHandlerHandlerProviderFactory, DelegatingHandlerHandlerProviderFactory>();
_services.TryAddSingleton<IDelegatingHandlerHandlerHouse, DelegatingHandlerHandlerHouse>();
_services.TryAddSingleton<IDelegatingHandlerHandlerFactory, DelegatingHandlerHandlerFactory>();
// 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
@ -144,9 +142,6 @@ namespace Ocelot.DependencyInjection
_services.AddWebEncoders();
_services.AddSingleton<IAdministrationPath>(new NullAdministrationPath());
//these get picked out later and added to http request
_provider = new DelegatingHandlerHandlerProvider();
_services.TryAddSingleton<IDelegatingHandlerHandlerProvider>(_provider);
_services.TryAddSingleton<IMultiplexer, Multiplexer>();
_services.TryAddSingleton<IResponseAggregator, SimpleJsonResponseAggregator>();
_services.AddSingleton<ITracingHandlerFactory, TracingHandlerFactory>();
@ -187,9 +182,10 @@ namespace Ocelot.DependencyInjection
return new OcelotAdministrationBuilder(_services, _configurationRoot);
}
public IOcelotBuilder AddDelegatingHandler(Func<DelegatingHandler> delegatingHandler)
public IOcelotBuilder AddDelegatingHandler<THandler>()
where THandler : DelegatingHandler
{
_provider.Add(delegatingHandler);
_services.AddSingleton<DelegatingHandler, THandler>();
return this;
}

View File

@ -1,58 +0,0 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using Ocelot.Configuration;
using Ocelot.Errors;
using Ocelot.Responses;
namespace Ocelot.Requester
{
public class DelegatingHandlerHandlerHouse : IDelegatingHandlerHandlerHouse
{
private readonly IDelegatingHandlerHandlerProviderFactory _factory;
private readonly ConcurrentDictionary<string, IDelegatingHandlerHandlerProvider> _housed;
public DelegatingHandlerHandlerHouse(IDelegatingHandlerHandlerProviderFactory factory)
{
_factory = factory;
_housed = new ConcurrentDictionary<string, IDelegatingHandlerHandlerProvider>();
}
public Response<IDelegatingHandlerHandlerProvider> Get(DownstreamReRoute request)
{
try
{
if (_housed.TryGetValue(request.ReRouteKey, out var provider))
{
//todo once day we might need a check here to see if we need to create a new provider
provider = _housed[request.ReRouteKey];
return new OkResponse<IDelegatingHandlerHandlerProvider>(provider);
}
//todo - unit test for this
var providerResponse = _factory.Get(request);
if (providerResponse.IsError)
{
return new ErrorResponse<IDelegatingHandlerHandlerProvider>(providerResponse.Errors);
}
provider = providerResponse.Data;
AddHoused(request.ReRouteKey, provider);
return new OkResponse<IDelegatingHandlerHandlerProvider>(provider);
}
catch (Exception ex)
{
return new ErrorResponse<IDelegatingHandlerHandlerProvider>(new List<Error>()
{
new UnableToFindDelegatingHandlerProviderError($"unabe to find delegating handler provider for {request.ReRouteKey} exception is {ex}")
});
}
}
private void AddHoused(string key, IDelegatingHandlerHandlerProvider provider)
{
_housed.AddOrUpdate(key, provider, (k, v) => provider);
}
}
}

View File

@ -1,28 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
namespace Ocelot.Requester
{
public class DelegatingHandlerHandlerProvider : IDelegatingHandlerHandlerProvider
{
private readonly Dictionary<int, Func<DelegatingHandler>> _handlers;
public DelegatingHandlerHandlerProvider()
{
_handlers = new Dictionary<int, Func<DelegatingHandler>>();
}
public void Add(Func<DelegatingHandler> handler)
{
var key = _handlers.Count == 0 ? 0 : _handlers.Count + 1;
_handlers[key] = handler;
}
public List<Func<DelegatingHandler>> Get()
{
return _handlers.Count > 0 ? _handlers.OrderBy(x => x.Key).Select(x => x.Value).ToList() : new List<Func<DelegatingHandler>>();
}
}
}

View File

@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using Microsoft.Extensions.DependencyInjection;
using Ocelot.Configuration;
using Ocelot.Logging;
using Ocelot.Requester.QoS;
@ -7,38 +9,38 @@ using Ocelot.Responses;
namespace Ocelot.Requester
{
public class DelegatingHandlerHandlerProviderFactory : IDelegatingHandlerHandlerProviderFactory
public class DelegatingHandlerHandlerFactory : IDelegatingHandlerHandlerFactory
{
private readonly ITracingHandlerFactory _factory;
private readonly IOcelotLoggerFactory _loggerFactory;
private readonly IDelegatingHandlerHandlerProvider _allRoutesProvider;
private readonly IQosProviderHouse _qosProviderHouse;
private readonly IServiceProvider _serviceProvider;
public DelegatingHandlerHandlerProviderFactory(IOcelotLoggerFactory loggerFactory,
IDelegatingHandlerHandlerProvider allRoutesProvider,
public DelegatingHandlerHandlerFactory(IOcelotLoggerFactory loggerFactory,
ITracingHandlerFactory factory,
IQosProviderHouse qosProviderHouse)
IQosProviderHouse qosProviderHouse,
IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
_factory = factory;
_loggerFactory = loggerFactory;
_allRoutesProvider = allRoutesProvider;
_qosProviderHouse = qosProviderHouse;
}
public Response<IDelegatingHandlerHandlerProvider> Get(DownstreamReRoute request)
public Response<List<Func<DelegatingHandler>>> Get(DownstreamReRoute request)
{
var handlersAppliedToAll = _allRoutesProvider.Get();
var handlersAppliedToAll = _serviceProvider.GetServices<DelegatingHandler>();
var provider = new DelegatingHandlerHandlerProvider();
var handlers = new List<Func<DelegatingHandler>>();
foreach (var handler in handlersAppliedToAll)
{
provider.Add(handler);
handlers.Add(() => handler);
}
if (request.HttpHandlerOptions.UseTracing)
{
provider.Add(() => (DelegatingHandler)_factory.Get());
handlers.Add(() => (DelegatingHandler)_factory.Get());
}
if (request.IsQos)
@ -47,13 +49,13 @@ namespace Ocelot.Requester
if (qosProvider.IsError)
{
return new ErrorResponse<IDelegatingHandlerHandlerProvider>(qosProvider.Errors);
return new ErrorResponse<List<Func<DelegatingHandler>>>(qosProvider.Errors);
}
provider.Add(() => new PollyCircuitBreakingDelegatingHandler(qosProvider.Data, _loggerFactory));
handlers.Add(() => new PollyCircuitBreakingDelegatingHandler(qosProvider.Data, _loggerFactory));
}
return new OkResponse<IDelegatingHandlerHandlerProvider>(provider);
return new OkResponse<List<Func<DelegatingHandler>>>(handlers);
}
}
}

View File

@ -6,11 +6,11 @@ namespace Ocelot.Requester
{
public class HttpClientBuilder : IHttpClientBuilder
{
private readonly IDelegatingHandlerHandlerHouse _house;
private readonly IDelegatingHandlerHandlerFactory _factory;
public HttpClientBuilder(IDelegatingHandlerHandlerHouse house)
public HttpClientBuilder(IDelegatingHandlerHandlerFactory house)
{
_house = house;
_factory = house;
}
public IHttpClient Create(DownstreamReRoute request)
@ -24,11 +24,9 @@ namespace Ocelot.Requester
private HttpMessageHandler CreateHttpMessageHandler(HttpMessageHandler httpMessageHandler, DownstreamReRoute request)
{
var provider = _house.Get(request);
var handlers = provider.Data.Get();
//todo handle error
var handlers = _factory.Get(request).Data;
handlers
.Select(handler => handler)
.Reverse()

View File

@ -13,20 +13,20 @@ namespace Ocelot.Requester
{
private readonly IHttpClientCache _cacheHandlers;
private readonly IOcelotLogger _logger;
private readonly IDelegatingHandlerHandlerHouse _house;
private readonly IDelegatingHandlerHandlerFactory _factory;
public HttpClientHttpRequester(IOcelotLoggerFactory loggerFactory,
IHttpClientCache cacheHandlers,
IDelegatingHandlerHandlerHouse house)
IDelegatingHandlerHandlerFactory house)
{
_logger = loggerFactory.CreateLogger<HttpClientHttpRequester>();
_cacheHandlers = cacheHandlers;
_house = house;
_factory = house;
}
public async Task<Response<HttpResponseMessage>> GetResponse(DownstreamContext request)
{
var builder = new HttpClientBuilder(_house);
var builder = new HttpClientBuilder(_factory);
var cacheKey = GetCacheKey(request);

View File

@ -1,10 +0,0 @@
using Ocelot.Configuration;
using Ocelot.Responses;
namespace Ocelot.Requester
{
public interface IDelegatingHandlerHandlerHouse
{
Response<IDelegatingHandlerHandlerProvider> Get(DownstreamReRoute request);
}
}

View File

@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
namespace Ocelot.Requester
{
public interface IDelegatingHandlerHandlerProvider
{
void Add(Func<DelegatingHandler> handler);
List<Func<DelegatingHandler>> Get();
}
}

View File

@ -1,10 +1,13 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using Ocelot.Configuration;
using Ocelot.Responses;
namespace Ocelot.Requester
{
public interface IDelegatingHandlerHandlerProviderFactory
public interface IDelegatingHandlerHandlerFactory
{
Response<IDelegatingHandlerHandlerProvider> Get(DownstreamReRoute request);
Response<List<Func<DelegatingHandler>>> Get(DownstreamReRoute request);
}
}