mirror of
https://github.com/nsnail/Ocelot.git
synced 2025-04-22 18:32:51 +08:00
This commit is contained in:
parent
a419ed68dc
commit
c8b72f31b5
@ -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
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"projects": [ "src", "test" ],
|
"projects": [ "src", "test" ],
|
||||||
"sdk": {
|
"sdk": {
|
||||||
"version": "2.1.300"
|
"version": "2.1.301"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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>()
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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 =>
|
||||||
{
|
{
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user