diff --git a/src/Ocelot/Configuration/Provider/YamlOcelotConfigurationProvider.cs b/src/Ocelot/Configuration/Provider/OcelotConfigurationProvider.cs
similarity index 50%
rename from src/Ocelot/Configuration/Provider/YamlOcelotConfigurationProvider.cs
rename to src/Ocelot/Configuration/Provider/OcelotConfigurationProvider.cs
index 2a92f786..4b6c5fd2 100644
--- a/src/Ocelot/Configuration/Provider/YamlOcelotConfigurationProvider.cs
+++ b/src/Ocelot/Configuration/Provider/OcelotConfigurationProvider.cs
@@ -7,12 +7,12 @@ namespace Ocelot.Configuration.Provider
///
/// Register as singleton
///
- public class YamlOcelotConfigurationProvider : IOcelotConfigurationProvider
+ public class OcelotConfigurationProvider : IOcelotConfigurationProvider
{
private readonly IOcelotConfigurationRepository _repo;
private readonly IOcelotConfigurationCreator _creator;
- public YamlOcelotConfigurationProvider(IOcelotConfigurationRepository repo,
+ public OcelotConfigurationProvider(IOcelotConfigurationRepository repo,
IOcelotConfigurationCreator creator)
{
_repo = repo;
@@ -21,28 +21,28 @@ namespace Ocelot.Configuration.Provider
public Response Get()
{
- var config = _repo.Get();
+ var repoConfig = _repo.Get();
- if (config.IsError)
+ if (repoConfig.IsError)
{
- return new ErrorResponse(config.Errors);
+ return new ErrorResponse(repoConfig.Errors);
}
- if (config.Data == null)
+ if (repoConfig.Data == null)
{
- var configuration = _creator.Create();
+ var creatorConfig = _creator.Create();
- if (configuration.IsError)
+ if (creatorConfig.IsError)
{
- return new ErrorResponse(configuration.Errors);
+ return new ErrorResponse(creatorConfig.Errors);
}
- _repo.AddOrReplace(configuration.Data);
+ _repo.AddOrReplace(creatorConfig.Data);
- return new OkResponse(configuration.Data);
+ return new OkResponse(creatorConfig.Data);
}
- return new OkResponse(config.Data);
+ return new OkResponse(repoConfig.Data);
}
}
}
\ No newline at end of file
diff --git a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs
index 6ed8a88d..0b943b19 100644
--- a/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs
+++ b/src/Ocelot/DependencyInjection/ServiceCollectionExtensions.cs
@@ -34,7 +34,7 @@ namespace Ocelot.DependencyInjection
// ocelot services.
services.AddSingleton();
- services.AddSingleton();
+ services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
diff --git a/src/Ocelot/Middleware/OcelotMiddlewareConfiguration.cs b/src/Ocelot/Middleware/OcelotMiddlewareConfiguration.cs
new file mode 100644
index 00000000..798c4577
--- /dev/null
+++ b/src/Ocelot/Middleware/OcelotMiddlewareConfiguration.cs
@@ -0,0 +1,27 @@
+namespace Ocelot.Middleware
+{
+ using System;
+ using System.Threading.Tasks;
+ using Microsoft.AspNetCore.Http;
+
+ public class OcelotMiddlewareConfiguration
+ {
+ public Func, Task> PreHttpResponderMiddleware { get; set; }
+ public Func, Task> PostHttpResponderMiddleware { get; set; }
+ public Func, Task> PreDownstreamRouteFinderMiddleware { get; set; }
+ public Func, Task> PostDownstreamRouteFinderMiddleware { get; set; }
+ public Func, Task> PreAuthenticationMiddleware { get; set; }
+ public Func, Task> PostAuthenticationMiddleware { get; set; }
+ public Func, Task> PreClaimsBuilderMiddleware { get; set; }
+ public Func, Task> PostClaimsBuilderMiddleware { get; set; }
+ public Func, Task> PreAuthorisationMiddleware { get; set; }
+ public Func, Task> PostAuthorisationMiddleware { get; set; }
+ public Func, Task> PreHttpRequestHeadersBuilderMiddleware { get; set; }
+ public Func, Task> PostHttpRequestHeadersBuilderMiddleware { get; set; }
+ public Func, Task> PreDownstreamUrlCreatorMiddleware { get; set; }
+ public Func, Task> PostDownstreamUrlCreatorMiddleware { get; set; }
+ public Func, Task> PreHttpRequestBuilderMiddleware { get; set; }
+ public Func, Task> PostHttpRequestBuilderMiddleware { get; set; }
+ public Func, Task> PreHttpRequesterMiddleware { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs b/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs
index 866ac4e8..8fe0877f 100644
--- a/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs
+++ b/src/Ocelot/Middleware/OcelotMiddlewareExtensions.cs
@@ -9,8 +9,11 @@ using Ocelot.Responder.Middleware;
namespace Ocelot.Middleware
{
+ using System;
+ using System.Threading.Tasks;
using Authorisation.Middleware;
using ClaimsBuilder.Middleware;
+ using Microsoft.AspNetCore.Http;
public static class OcelotMiddlewareExtensions
{
@@ -36,5 +39,70 @@ namespace Ocelot.Middleware
return builder;
}
+
+ public static IApplicationBuilder UseOcelot(this IApplicationBuilder builder, OcelotMiddlewareConfiguration middlewareConfiguration)
+ {
+ builder.UseIfNotNull(middlewareConfiguration.PreHttpResponderMiddleware);
+
+ builder.UseHttpResponderMiddleware();
+
+ builder.UseIfNotNull(middlewareConfiguration.PostHttpResponderMiddleware);
+
+ builder.UseIfNotNull(middlewareConfiguration.PreDownstreamRouteFinderMiddleware);
+
+ builder.UseDownstreamRouteFinderMiddleware();
+
+ builder.UseIfNotNull(middlewareConfiguration.PostDownstreamRouteFinderMiddleware);
+
+ builder.UseIfNotNull(middlewareConfiguration.PreAuthenticationMiddleware);
+
+ builder.UseAuthenticationMiddleware();
+
+ builder.UseIfNotNull(middlewareConfiguration.PostAuthenticationMiddleware);
+
+ builder.UseIfNotNull(middlewareConfiguration.PreClaimsBuilderMiddleware);
+
+ builder.UseClaimsBuilderMiddleware();
+
+ builder.UseIfNotNull(middlewareConfiguration.PostClaimsBuilderMiddleware);
+
+ builder.UseIfNotNull(middlewareConfiguration.PreAuthorisationMiddleware);
+
+ builder.UseAuthorisationMiddleware();
+
+ builder.UseIfNotNull(middlewareConfiguration.PostAuthorisationMiddleware);
+
+ builder.UseIfNotNull(middlewareConfiguration.PreHttpRequestHeadersBuilderMiddleware);
+
+ builder.UseHttpRequestHeadersBuilderMiddleware();
+
+ builder.UseIfNotNull(middlewareConfiguration.PostHttpRequestHeadersBuilderMiddleware);
+
+ builder.UseIfNotNull(middlewareConfiguration.PreDownstreamUrlCreatorMiddleware);
+
+ builder.UseDownstreamUrlCreatorMiddleware();
+
+ builder.UseIfNotNull(middlewareConfiguration.PostDownstreamUrlCreatorMiddleware);
+
+ builder.UseIfNotNull(middlewareConfiguration.PreHttpRequestBuilderMiddleware);
+
+ builder.UseHttpRequestBuilderMiddleware();
+
+ builder.UseIfNotNull(middlewareConfiguration.PostHttpRequestBuilderMiddleware);
+
+ builder.UseIfNotNull(middlewareConfiguration.PreHttpRequesterMiddleware);
+
+ builder.UseHttpRequesterMiddleware();
+
+ return builder;
+ }
+
+ private static void UseIfNotNull(this IApplicationBuilder builder, Func, Task> middleware)
+ {
+ if (middleware != null)
+ {
+ builder.Use(middleware);
+ }
+ }
}
}
diff --git a/test/Ocelot.AcceptanceTests/CustomMiddlewareTests.cs b/test/Ocelot.AcceptanceTests/CustomMiddlewareTests.cs
new file mode 100644
index 00000000..d7b680a5
--- /dev/null
+++ b/test/Ocelot.AcceptanceTests/CustomMiddlewareTests.cs
@@ -0,0 +1,201 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Net;
+using System.Net.Http;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.TestHost;
+using Ocelot.Configuration.Yaml;
+using Shouldly;
+using TestStack.BDDfy;
+using Xunit;
+using YamlDotNet.Serialization;
+
+namespace Ocelot.AcceptanceTests
+{
+ using System.Linq;
+ using System.Threading.Tasks;
+ using DependencyInjection;
+ using Microsoft.Extensions.Configuration;
+ using Microsoft.Extensions.DependencyInjection;
+ using Microsoft.Extensions.Logging;
+ using Microsoft.Extensions.Primitives;
+ using Middleware;
+ using ScopedData;
+
+ public class CustomMiddlewareTests : IDisposable
+ {
+ private TestServer _server;
+ private HttpClient _client;
+ private HttpResponseMessage _response;
+ private readonly string _configurationPath;
+ private StringContent _postContent;
+ private IWebHost _builder;
+
+ // Sadly we need to change this when we update the netcoreapp version to make the test update the config correctly
+ private double _netCoreAppVersion = 1.4;
+
+ public CustomMiddlewareTests()
+ {
+ _configurationPath = $"configuration.yaml";
+ }
+
+ [Fact]
+ public void response_should_come_from_pre_http_responder_middleware()
+ {
+ var configuration = new OcelotMiddlewareConfiguration
+ {
+ PreHttpResponderMiddleware = async (ctx, next) =>
+ {
+ await ctx.Response.WriteAsync("PreHttpResponderMiddleware");
+ }
+ };
+
+ this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:41879", 200))
+ .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration
+ {
+ ReRoutes = new List
+ {
+ new YamlReRoute
+ {
+ DownstreamTemplate = "http://localhost:41879/",
+ UpstreamTemplate = "/",
+ UpstreamHttpMethod = "Get",
+ }
+ }
+ }))
+ .And(x => x.GivenTheApiGatewayIsRunning(configuration))
+ .When(x => x.WhenIGetUrlOnTheApiGateway("/"))
+ .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
+ .And(x => x.ThenTheResponseBodyShouldBe("PreHttpResponderMiddleware"))
+ .BDDfy();
+ }
+
+ [Fact]
+ public void response_should_come_from_pre_http_requester_middleware()
+ {
+ var configuration = new OcelotMiddlewareConfiguration
+ {
+ PreHttpRequesterMiddleware = async (ctx, next) =>
+ {
+ var service = ctx.RequestServices.GetService();
+ service.Add("Response",
+ new HttpResponseMessage {Content = new StringContent("PreHttpRequesterMiddleware")});
+ }
+ };
+
+ this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:41879", 200))
+ .And(x => x.GivenThereIsAConfiguration(new YamlConfiguration
+ {
+ ReRoutes = new List
+ {
+ new YamlReRoute
+ {
+ DownstreamTemplate = "http://localhost:41879/",
+ UpstreamTemplate = "/",
+ UpstreamHttpMethod = "Get",
+ }
+ }
+ }))
+ .And(x => x.GivenTheApiGatewayIsRunning(configuration))
+ .When(x => x.WhenIGetUrlOnTheApiGateway("/"))
+ .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
+ .And(x => x.ThenTheResponseBodyShouldBe("PreHttpRequesterMiddleware"))
+ .BDDfy();
+ }
+
+
+
+ ///
+ /// This is annoying cos it should be in the constructor but we need to set up the yaml file before calling startup so its a step.
+ ///
+ private void GivenTheApiGatewayIsRunning(OcelotMiddlewareConfiguration ocelotMiddlewareConfig)
+ {
+ var builder = new ConfigurationBuilder()
+ .SetBasePath(Directory.GetCurrentDirectory())
+ .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
+ .AddYamlFile("configuration.yaml")
+ .AddEnvironmentVariables();
+
+ var configuration = builder.Build();
+
+ _server = new TestServer(new WebHostBuilder()
+ .UseConfiguration(configuration)
+ .ConfigureServices(s =>
+ {
+ s.AddOcelotYamlConfiguration(configuration);
+ s.AddOcelot();
+ })
+ .ConfigureLogging(l =>
+ {
+ l.AddConsole(configuration.GetSection("Logging"));
+ l.AddDebug();
+ })
+ .Configure(a =>
+ {
+ a.UseOcelot(ocelotMiddlewareConfig);
+ }));
+
+ _client = _server.CreateClient();
+ }
+
+ private void GivenThereIsAConfiguration(YamlConfiguration yamlConfiguration)
+ {
+ var serializer = new Serializer();
+
+ if (File.Exists(_configurationPath))
+ {
+ File.Delete(_configurationPath);
+ }
+
+ using (TextWriter writer = File.CreateText(_configurationPath))
+ {
+ serializer.Serialize(writer, yamlConfiguration);
+ }
+ }
+
+ private void GivenThereIsAServiceRunningOn(string url, int statusCode)
+ {
+ _builder = new WebHostBuilder()
+ .UseUrls(url)
+ .UseKestrel()
+ .UseContentRoot(Directory.GetCurrentDirectory())
+ .UseIISIntegration()
+ .UseUrls(url)
+ .Configure(app =>
+ {
+ app.Run(async context =>
+ {
+ context.Response.StatusCode = statusCode;
+ });
+ })
+ .Build();
+
+ _builder.Start();
+ }
+
+ private void WhenIGetUrlOnTheApiGateway(string url)
+ {
+ _response = _client.GetAsync(url).Result;
+ }
+
+ private void ThenTheStatusCodeShouldBe(HttpStatusCode expectedHttpStatusCode)
+ {
+ _response.StatusCode.ShouldBe(expectedHttpStatusCode);
+ }
+
+ private void ThenTheResponseBodyShouldBe(string expectedBody)
+ {
+ _response.Content.ReadAsStringAsync().Result.ShouldBe(expectedBody);
+ }
+
+ public void Dispose()
+ {
+ _builder?.Dispose();
+ _client.Dispose();
+ _server.Dispose();
+ }
+ }
+}
diff --git a/test/Ocelot.AcceptanceTests/configuration.yaml b/test/Ocelot.AcceptanceTests/configuration.yaml
index 29e93d20..feba804e 100644
--- a/test/Ocelot.AcceptanceTests/configuration.yaml
+++ b/test/Ocelot.AcceptanceTests/configuration.yaml
@@ -1,13 +1,7 @@
ReRoutes:
-- DownstreamTemplate: http://localhost:51876/
+- DownstreamTemplate: http://localhost:41879/
UpstreamTemplate: /
- UpstreamHttpMethod: Post
- AuthenticationOptions:
- Provider: IdentityServer
- ProviderRootUrl: http://localhost:51888
- ScopeName: api
- AdditionalScopes: []
- ScopeSecret: secret
- ProxyRequestHeaders:
- - CustomerId: Claims[CustomerId]
-
+ UpstreamHttpMethod: Get
+ AddHeadersToRequest: {}
+ AddClaimsToRequest: {}
+ RouteClaimsRequirement: {}
diff --git a/test/Ocelot.AcceptanceTests/project.json b/test/Ocelot.AcceptanceTests/project.json
index 56f49099..0ff6cf15 100644
--- a/test/Ocelot.AcceptanceTests/project.json
+++ b/test/Ocelot.AcceptanceTests/project.json
@@ -4,7 +4,7 @@
"buildOptions": {
"copyToOutput": {
"include": [
- "configuration.yaml"
+ "middlewareConfiguration.yaml"
]
}
},
diff --git a/test/Ocelot.ManualTest/project.json b/test/Ocelot.ManualTest/project.json
index 39425e9d..921118bd 100644
--- a/test/Ocelot.ManualTest/project.json
+++ b/test/Ocelot.ManualTest/project.json
@@ -39,7 +39,7 @@
"preserveCompilationContext": true,
"copyToOutput": {
"include": [
- "configuration.yaml"
+ "middlewareConfiguration.yaml"
]
}
},
@@ -57,7 +57,7 @@
"Areas/**/Views",
"appsettings.json",
"web.config",
- "configuration.yaml"
+ "middlewareConfiguration.yaml"
]
},
diff --git a/test/Ocelot.ManualTest/web.config b/test/Ocelot.ManualTest/web.config
index dc0514fc..894788ec 100644
--- a/test/Ocelot.ManualTest/web.config
+++ b/test/Ocelot.ManualTest/web.config
@@ -1,5 +1,5 @@
-
+