#438 removed singleton delegating handlers as you cannot have these (#456)

This commit is contained in:
Tom Pallister 2018-07-09 08:08:39 +01:00 committed by GitHub
parent a419ed68dc
commit c8b72f31b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 643 additions and 601 deletions

View File

@ -1,5 +1,5 @@
Delegating Handers Delegating Handlers
================== ===================
Ocelot allows the user to add delegating handlers to the HttpClient transport. This feature was requested `GitHub #208 <https://github.com/TomPallister/Ocelot/issues/208>`_ Ocelot allows the user to add delegating handlers to the HttpClient transport. This feature was requested `GitHub #208 <https://github.com/TomPallister/Ocelot/issues/208>`_
and I decided that it was going to be useful in various ways. Since then we extended it in `GitHub #264 <https://github.com/TomPallister/Ocelot/issues/264>`_. and I decided that it was going to be useful in various ways. Since then we extended it in `GitHub #264 <https://github.com/TomPallister/Ocelot/issues/264>`_.
@ -23,21 +23,13 @@ asp.net core container so you can inject any other services you have registered
} }
} }
Next you must add the handlers to Ocelot's container either as singleton like follows.. Next you must add the handlers to Ocelot's container like below...
.. code-block:: csharp .. code-block:: csharp
services.AddOcelot() services.AddOcelot()
.AddSingletonDelegatingHandler<FakeHandler>() .AddDelegatingHandler<FakeHandler>()
.AddSingletonDelegatingHandler<FakeHandlerTwo>() .AddDelegatingHandler<FakeHandlerTwo>()
Or transient as below...
.. code-block:: csharp
services.AddOcelot()
.AddTransientDelegatingHandler<FakeHandler>()
.AddTransientDelegatingHandler<FakeHandlerTwo>()
Both of these Add methods have a default parameter called global which is set to false. If it is false then the intent of Both of these Add methods have a default parameter called global which is set to false. If it is false then the intent of
the DelegatingHandler is to be applied to specific ReRoutes via ocelot.json (more on that later). If it is set to true the DelegatingHandler is to be applied to specific ReRoutes via ocelot.json (more on that later). If it is set to true
@ -45,17 +37,12 @@ then it becomes a global handler and will be applied to all ReRoutes.
e.g. e.g.
.. code-block:: csharp As below...
services.AddOcelot()
.AddSingletonDelegatingHandler<FakeHandler>(true)
Or transient as below...
.. code-block:: csharp .. code-block:: csharp
services.AddOcelot() services.AddOcelot()
.AddTransientDelegatingHandler<FakeHandler>(true) .AddDelegatingHandler<FakeHandler>(true)
Finally if you want ReRoute specific DelegatingHandlers or to order your specific and / or global (more on this later) DelegatingHandlers Finally if you want ReRoute specific DelegatingHandlers or to order your specific and / or global (more on this later) DelegatingHandlers
then you must add the following json to the specific ReRoute in ocelot.json. The names in the array must match the class names of your then you must add the following json to the specific ReRoute in ocelot.json. The names in the array must match the class names of your

View File

@ -1,6 +1,6 @@
{ {
"projects": [ "src", "test" ], "projects": [ "src", "test" ],
"sdk": { "sdk": {
"version": "2.1.300" "version": "2.1.301"
} }
} }

View File

@ -19,10 +19,7 @@ namespace Ocelot.DependencyInjection
IOcelotAdministrationBuilder AddAdministration(string path, Action<IdentityServerAuthenticationOptions> configOptions); IOcelotAdministrationBuilder AddAdministration(string path, Action<IdentityServerAuthenticationOptions> configOptions);
IOcelotBuilder AddSingletonDelegatingHandler<T>(bool global = false) IOcelotBuilder AddDelegatingHandler<T>(bool global = false)
where T : DelegatingHandler;
IOcelotBuilder AddTransientDelegatingHandler<T>(bool global = false)
where T : DelegatingHandler; where T : DelegatingHandler;
IOcelotBuilder AddSingletonDefinedAggregator<T>() IOcelotBuilder AddSingletonDefinedAggregator<T>()

View File

@ -212,26 +212,7 @@ namespace Ocelot.DependencyInjection
return this; return this;
} }
public IOcelotBuilder AddSingletonDelegatingHandler<THandler>(bool global = false) public IOcelotBuilder AddDelegatingHandler<THandler>(bool global = false)
where THandler : DelegatingHandler
{
if(global)
{
_services.AddSingleton<THandler>();
_services.AddSingleton<GlobalDelegatingHandler>(s => {
var service = s.GetService<THandler>();
return new GlobalDelegatingHandler(service);
});
}
else
{
_services.AddSingleton<DelegatingHandler, THandler>();
}
return this;
}
public IOcelotBuilder AddTransientDelegatingHandler<THandler>(bool global = false)
where THandler : DelegatingHandler where THandler : DelegatingHandler
{ {
if(global) if(global)

View File

@ -101,6 +101,57 @@ namespace Ocelot.AcceptanceTests
.BDDfy(); .BDDfy();
} }
[Fact]
public void should_call_global_di_handlers_multiple_times()
{
var configuration = new FileConfiguration
{
ReRoutes = new List<FileReRoute>
{
new FileReRoute
{
DownstreamPathTemplate = "/",
DownstreamScheme = "http",
DownstreamHostAndPorts = new List<FileHostAndPort>
{
new FileHostAndPort
{
Host = "localhost",
Port = 9187,
}
},
UpstreamPathTemplate = "/",
UpstreamHttpMethod = new List<string> { "Get" },
}
}
};
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:9187", "/", 200, "Hello from Laura"))
.And(x => _steps.GivenThereIsAConfiguration(configuration))
.And(x => _steps.GivenOcelotIsRunningWithGlobalHandlerRegisteredInDi<FakeHandlerAgain>())
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
.BDDfy();
}
[Fact] [Fact]
public void should_call_global_di_handlers_with_dependency() public void should_call_global_di_handlers_with_dependency()
{ {
@ -198,6 +249,17 @@ namespace Ocelot.AcceptanceTests
return base.SendAsync(request, cancellationToken); return base.SendAsync(request, cancellationToken);
} }
} }
// ReSharper disable once ClassNeverInstantiated.Local
private class FakeHandlerAgain : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
Console.WriteLine(request.RequestUri);
//do stuff and optionally call the base handler..
return await base.SendAsync(request, cancellationToken);
}
}
private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode, string responseBody) private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode, string responseBody)
{ {

View File

@ -237,8 +237,8 @@ namespace Ocelot.AcceptanceTests
{ {
s.AddSingleton(_webHostBuilder); s.AddSingleton(_webHostBuilder);
s.AddOcelot() s.AddOcelot()
.AddSingletonDelegatingHandler<TOne>() .AddDelegatingHandler<TOne>()
.AddSingletonDelegatingHandler<TWo>(); .AddDelegatingHandler<TWo>();
}) })
.Configure(a => .Configure(a =>
{ {
@ -303,8 +303,39 @@ namespace Ocelot.AcceptanceTests
{ {
s.AddSingleton(_webHostBuilder); s.AddSingleton(_webHostBuilder);
s.AddOcelot() s.AddOcelot()
.AddSingletonDelegatingHandler<TOne>(true) .AddDelegatingHandler<TOne>(true)
.AddSingletonDelegatingHandler<TWo>(true); .AddDelegatingHandler<TWo>(true);
})
.Configure(a =>
{
a.UseOcelot().Wait();
});
_ocelotServer = new TestServer(_webHostBuilder);
_ocelotClient = _ocelotServer.CreateClient();
}
public void GivenOcelotIsRunningWithGlobalHandlerRegisteredInDi<TOne>()
where TOne : DelegatingHandler
{
_webHostBuilder = new WebHostBuilder();
_webHostBuilder
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
var env = hostingContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
config.AddJsonFile("ocelot.json");
config.AddEnvironmentVariables();
})
.ConfigureServices(s =>
{
s.AddSingleton(_webHostBuilder);
s.AddOcelot()
.AddDelegatingHandler<TOne>(true);
}) })
.Configure(a => .Configure(a =>
{ {
@ -336,7 +367,7 @@ namespace Ocelot.AcceptanceTests
s.AddSingleton(_webHostBuilder); s.AddSingleton(_webHostBuilder);
s.AddSingleton<FakeDependency>(dependency); s.AddSingleton<FakeDependency>(dependency);
s.AddOcelot() s.AddOcelot()
.AddSingletonDelegatingHandler<TOne>(true); .AddDelegatingHandler<TOne>(true);
}) })
.Configure(a => .Configure(a =>
{ {

View File

@ -9,6 +9,9 @@
using Ocelot.Middleware; using Ocelot.Middleware;
using System; using System;
using IdentityServer4.AccessTokenValidation; using IdentityServer4.AccessTokenValidation;
using System.Net.Http;
using System.Threading.Tasks;
using System.Threading;
public class Program public class Program
{ {
@ -35,10 +38,11 @@
}); });
s.AddOcelot() s.AddOcelot()
.AddCacheManager(x => .AddDelegatingHandler<FakeHandler>(true)
{ // .AddCacheManager(x =>
x.WithDictionaryHandle(); // {
}) // x.WithDictionaryHandle();
// })
/*.AddOpenTracing(option => /*.AddOpenTracing(option =>
{ {
option.CollectorUrl = "http://localhost:9618"; option.CollectorUrl = "http://localhost:9618";
@ -60,4 +64,15 @@
.Run(); .Run();
} }
} }
public class FakeHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
Console.WriteLine(request.RequestUri);
//do stuff and optionally call the base handler..
return await base.SendAsync(request, cancellationToken);
}
}
} }

View File

@ -52,17 +52,6 @@ namespace Ocelot.UnitTests.DependencyInjection
.BDDfy(); .BDDfy();
} }
[Fact]
public void should_add_specific_delegating_handler_singleton()
{
this.Given(x => WhenISetUpOcelotServices())
.When(x => AddSpecificDelegatingHandler<FakeDelegatingHandler>())
.And(x => AddSpecificDelegatingHandler<FakeDelegatingHandlerTwo>())
.Then(x => ThenTheProviderIsRegisteredAndReturnsSpecificHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
.And(x => ThenTheSpecificHandlersAreSingleton())
.BDDfy();
}
[Fact] [Fact]
public void should_add_global_delegating_handlers_transient() public void should_add_global_delegating_handlers_transient()
{ {
@ -74,17 +63,6 @@ namespace Ocelot.UnitTests.DependencyInjection
.BDDfy(); .BDDfy();
} }
[Fact]
public void should_add_global_delegating_handlers_singleton()
{
this.Given(x => WhenISetUpOcelotServices())
.When(x => AddGlobalDelegatingHandler<FakeDelegatingHandler>())
.And(x => AddGlobalDelegatingHandler<FakeDelegatingHandlerTwo>())
.Then(x => ThenTheProviderIsRegisteredAndReturnsHandlers<FakeDelegatingHandler, FakeDelegatingHandlerTwo>())
.And(x => ThenTheGlobalHandlersAreSingleton())
.BDDfy();
}
[Fact] [Fact]
public void should_set_up_services() public void should_set_up_services()
{ {
@ -231,15 +209,6 @@ namespace Ocelot.UnitTests.DependencyInjection
first.ShouldNotBe(second); first.ShouldNotBe(second);
} }
private void ThenTheGlobalHandlersAreSingleton()
{
var handlers = _serviceProvider.GetServices<GlobalDelegatingHandler>().ToList();
var first = handlers[0].DelegatingHandler;
handlers = _serviceProvider.GetServices<GlobalDelegatingHandler>().ToList();
var second = handlers[0].DelegatingHandler;
first.ShouldBe(second);
}
private void ThenTheGlobalHandlersAreTransient() private void ThenTheGlobalHandlersAreTransient()
{ {
var handlers = _serviceProvider.GetServices<GlobalDelegatingHandler>().ToList(); var handlers = _serviceProvider.GetServices<GlobalDelegatingHandler>().ToList();
@ -262,13 +231,13 @@ namespace Ocelot.UnitTests.DependencyInjection
private void AddTransientGlobalDelegatingHandler<T>() private void AddTransientGlobalDelegatingHandler<T>()
where T : DelegatingHandler where T : DelegatingHandler
{ {
_ocelotBuilder.AddTransientDelegatingHandler<T>(true); _ocelotBuilder.AddDelegatingHandler<T>(true);
} }
private void AddSpecificTransientDelegatingHandler<T>() private void AddSpecificTransientDelegatingHandler<T>()
where T : DelegatingHandler where T : DelegatingHandler
{ {
_ocelotBuilder.AddTransientDelegatingHandler<T>(); _ocelotBuilder.AddDelegatingHandler<T>();
} }
private void ThenTheCorrectAdminPathIsRegitered() private void ThenTheCorrectAdminPathIsRegitered()
@ -365,13 +334,13 @@ namespace Ocelot.UnitTests.DependencyInjection
private void AddGlobalDelegatingHandler<T>() private void AddGlobalDelegatingHandler<T>()
where T : DelegatingHandler where T : DelegatingHandler
{ {
_ocelotBuilder.AddSingletonDelegatingHandler<T>(true); _ocelotBuilder.AddDelegatingHandler<T>(true);
} }
private void AddSpecificDelegatingHandler<T>() private void AddSpecificDelegatingHandler<T>()
where T : DelegatingHandler where T : DelegatingHandler
{ {
_ocelotBuilder.AddSingletonDelegatingHandler<T>(); _ocelotBuilder.AddDelegatingHandler<T>();
} }
private void ThenAnOcelotBuilderIsReturned() private void ThenAnOcelotBuilderIsReturned()