mirror of
https://github.com/nsnail/Ocelot.git
synced 2025-04-20 08:22:50 +08:00
#238 support passing statefull service headers to service fabric naming service
This commit is contained in:
parent
454ba3f9a0
commit
4a28666a41
@ -33,3 +33,11 @@ The example below is taken from the samples folder so please check it if this do
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
If you are using stateless / guest exe services ocelot will be able to proxy through the naming service without anything else. However
|
||||||
|
if you are using statefull / actor services you must send the PartitionKind and PartitionKey query string values with the client
|
||||||
|
request e.g.
|
||||||
|
|
||||||
|
GET http://ocelot.com/EquipmentInterfaces?PartitionKind=xxx&PartitionKey=xxx
|
||||||
|
|
||||||
|
There is no way for Ocelot to work these out for you.
|
||||||
|
@ -9,7 +9,7 @@ author: raunakpandya edited by Tom Pallister for Ocelot
|
|||||||
This shows a service fabric cluster with Ocelot exposed over HTTP accessing services in the cluster via the naming service. If you want to try and use Ocelot with
|
This shows a service fabric cluster with Ocelot exposed over HTTP accessing services in the cluster via the naming service. If you want to try and use Ocelot with
|
||||||
Service Fabric I reccomend using this as a starting point.
|
Service Fabric I reccomend using this as a starting point.
|
||||||
|
|
||||||
Ocelot does not support partitioned services (stateful & actors) at the moment.
|
If you want to use statefull / actors you must send the PartitionKind and PartitionKey to Ocelot as query string parameters.
|
||||||
|
|
||||||
I have not tested this sample on Service Fabric hosted on Linux just a Windows dev cluster. This sample assumes a good understanding of Service Fabric.
|
I have not tested this sample on Service Fabric hosted on Linux just a Windows dev cluster. This sample assumes a good understanding of Service Fabric.
|
||||||
|
|
||||||
|
@ -7,6 +7,8 @@ using Ocelot.Middleware;
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Ocelot.DownstreamRouteFinder.Middleware;
|
using Ocelot.DownstreamRouteFinder.Middleware;
|
||||||
|
using Ocelot.Responses;
|
||||||
|
using Ocelot.Values;
|
||||||
|
|
||||||
namespace Ocelot.DownstreamUrlCreator.Middleware
|
namespace Ocelot.DownstreamUrlCreator.Middleware
|
||||||
{
|
{
|
||||||
@ -40,21 +42,9 @@ namespace Ocelot.DownstreamUrlCreator.Middleware
|
|||||||
|
|
||||||
UriBuilder uriBuilder;
|
UriBuilder uriBuilder;
|
||||||
|
|
||||||
//todo - feel this is a bit crap the way we build the url dont see why we need this builder thing..maybe i blew my own brains out
|
if (ServiceFabricRequest(context))
|
||||||
// when i originally wrote it..
|
|
||||||
if (context.ServiceProviderConfiguration.Type == "ServiceFabric" && context.DownstreamReRoute.UseServiceDiscovery)
|
|
||||||
{
|
{
|
||||||
_logger.LogInformation("DownstreamUrlCreatorMiddleware - going to try set service fabric path");
|
uriBuilder = CreateServiceFabricUri(context, dsPath);
|
||||||
|
|
||||||
var scheme = context.DownstreamReRoute.DownstreamScheme;
|
|
||||||
var host = context.DownstreamRequest.RequestUri.Host;
|
|
||||||
var port = context.DownstreamRequest.RequestUri.Port;
|
|
||||||
var serviceFabricPath = $"/{context.DownstreamReRoute.ServiceName + dsPath.Data.Value}";
|
|
||||||
|
|
||||||
_logger.LogInformation("DownstreamUrlCreatorMiddleware - service fabric path is {proxyUrl}", serviceFabricPath);
|
|
||||||
|
|
||||||
var uri = new Uri($"{scheme}://{host}:{port}{serviceFabricPath}?cmd=instance");
|
|
||||||
uriBuilder = new UriBuilder(uri);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -71,5 +61,38 @@ namespace Ocelot.DownstreamUrlCreator.Middleware
|
|||||||
|
|
||||||
await _next.Invoke(context);
|
await _next.Invoke(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private UriBuilder CreateServiceFabricUri(DownstreamContext context, Response<DownstreamPath> dsPath)
|
||||||
|
{
|
||||||
|
var query = context.DownstreamRequest.RequestUri.Query;
|
||||||
|
var scheme = context.DownstreamReRoute.DownstreamScheme;
|
||||||
|
var host = context.DownstreamRequest.RequestUri.Host;
|
||||||
|
var port = context.DownstreamRequest.RequestUri.Port;
|
||||||
|
var serviceFabricPath = $"/{context.DownstreamReRoute.ServiceName + dsPath.Data.Value}";
|
||||||
|
|
||||||
|
Uri uri;
|
||||||
|
|
||||||
|
if (RequestForStatefullService(query))
|
||||||
|
{
|
||||||
|
uri = new Uri($"{scheme}://{host}:{port}{serviceFabricPath}{query}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var split = string.IsNullOrEmpty(query) ? "?" : "&";
|
||||||
|
uri = new Uri($"{scheme}://{host}:{port}{serviceFabricPath}{query}{split}cmd=instance");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new UriBuilder(uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool ServiceFabricRequest(DownstreamContext context)
|
||||||
|
{
|
||||||
|
return context.ServiceProviderConfiguration.Type == "ServiceFabric" && context.DownstreamReRoute.UseServiceDiscovery;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool RequestForStatefullService(string query)
|
||||||
|
{
|
||||||
|
return query.Contains("PartitionKind") && query.Contains("PartitionKey");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ namespace Ocelot.AcceptanceTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void should_support_service_fabric_naming_and_dns_service()
|
public void should_support_service_fabric_naming_and_dns_service_stateless_and_guest()
|
||||||
{
|
{
|
||||||
var configuration = new FileConfiguration
|
var configuration = new FileConfiguration
|
||||||
{
|
{
|
||||||
@ -54,7 +54,7 @@ namespace Ocelot.AcceptanceTests
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:19081", "/OcelotServiceApplication/OcelotApplicationService/api/values", 200, "Hello from Laura"))
|
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:19081", "/OcelotServiceApplication/OcelotApplicationService/api/values", 200, "Hello from Laura", "cmd=instance"))
|
||||||
.And(x => _steps.GivenThereIsAConfiguration(configuration))
|
.And(x => _steps.GivenThereIsAConfiguration(configuration))
|
||||||
.And(x => _steps.GivenOcelotIsRunning())
|
.And(x => _steps.GivenOcelotIsRunning())
|
||||||
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/EquipmentInterfaces"))
|
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/EquipmentInterfaces"))
|
||||||
@ -63,7 +63,44 @@ namespace Ocelot.AcceptanceTests
|
|||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode, string responseBody)
|
[Fact]
|
||||||
|
public void should_support_service_fabric_naming_and_dns_service_statefull_and_actors()
|
||||||
|
{
|
||||||
|
var configuration = new FileConfiguration
|
||||||
|
{
|
||||||
|
ReRoutes = new List<FileReRoute>
|
||||||
|
{
|
||||||
|
new FileReRoute
|
||||||
|
{
|
||||||
|
DownstreamPathTemplate = "/api/values",
|
||||||
|
DownstreamScheme = "http",
|
||||||
|
UpstreamPathTemplate = "/EquipmentInterfaces",
|
||||||
|
UpstreamHttpMethod = new List<string> { "Get" },
|
||||||
|
UseServiceDiscovery = true,
|
||||||
|
ServiceName = "OcelotServiceApplication/OcelotApplicationService"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
GlobalConfiguration = new FileGlobalConfiguration
|
||||||
|
{
|
||||||
|
ServiceDiscoveryProvider = new FileServiceDiscoveryProvider()
|
||||||
|
{
|
||||||
|
Host = "localhost",
|
||||||
|
Port = 19081,
|
||||||
|
Type = "ServiceFabric"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:19081", "/OcelotServiceApplication/OcelotApplicationService/api/values", 200, "Hello from Laura", "PartitionKind=test&PartitionKey=1"))
|
||||||
|
.And(x => _steps.GivenThereIsAConfiguration(configuration))
|
||||||
|
.And(x => _steps.GivenOcelotIsRunning())
|
||||||
|
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/EquipmentInterfaces?PartitionKind=test&PartitionKey=1"))
|
||||||
|
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
|
||||||
|
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode, string responseBody, string expectedQueryString)
|
||||||
{
|
{
|
||||||
_builder = new WebHostBuilder()
|
_builder = new WebHostBuilder()
|
||||||
.UseUrls(baseUrl)
|
.UseUrls(baseUrl)
|
||||||
@ -84,9 +121,8 @@ namespace Ocelot.AcceptanceTests
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (context.Request.Query.TryGetValue("cmd", out var values))
|
if (context.Request.QueryString.Value.Contains(expectedQueryString))
|
||||||
{
|
{
|
||||||
values.First().ShouldBe("instance");
|
|
||||||
context.Response.StatusCode = statusCode;
|
context.Response.StatusCode = statusCode;
|
||||||
await context.Response.WriteAsync(responseBody);
|
await context.Response.WriteAsync(responseBody);
|
||||||
}
|
}
|
||||||
|
@ -135,6 +135,66 @@ namespace Ocelot.UnitTests.DownstreamUrlCreator
|
|||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_create_service_fabric_url_with_query_string_for_stateless_service()
|
||||||
|
{
|
||||||
|
var downstreamReRoute = new DownstreamReRouteBuilder()
|
||||||
|
.WithDownstreamScheme("http")
|
||||||
|
.WithServiceName("Ocelot/OcelotApp")
|
||||||
|
.WithUseServiceDiscovery(true)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
var downstreamRoute = new DownstreamRoute(
|
||||||
|
new List<PlaceholderNameAndValue>(),
|
||||||
|
new ReRouteBuilder()
|
||||||
|
.WithDownstreamReRoute(downstreamReRoute)
|
||||||
|
.Build());
|
||||||
|
|
||||||
|
var config = new ServiceProviderConfigurationBuilder()
|
||||||
|
.WithServiceDiscoveryProviderType("ServiceFabric")
|
||||||
|
.WithServiceDiscoveryProviderHost("localhost")
|
||||||
|
.WithServiceDiscoveryProviderPort(19081)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
|
||||||
|
.And(x => GivenTheServiceProviderConfigIs(config))
|
||||||
|
.And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:19081?Tom=test&laura=1"))
|
||||||
|
.And(x => x.GivenTheUrlReplacerWillReturn("/api/products/1"))
|
||||||
|
.When(x => x.WhenICallTheMiddleware())
|
||||||
|
.Then(x => x.ThenTheDownstreamRequestUriIs("http://localhost:19081/Ocelot/OcelotApp/api/products/1?Tom=test&laura=1&cmd=instance"))
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void should_create_service_fabric_url_with_query_string_for_stateful_service()
|
||||||
|
{
|
||||||
|
var downstreamReRoute = new DownstreamReRouteBuilder()
|
||||||
|
.WithDownstreamScheme("http")
|
||||||
|
.WithServiceName("Ocelot/OcelotApp")
|
||||||
|
.WithUseServiceDiscovery(true)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
var downstreamRoute = new DownstreamRoute(
|
||||||
|
new List<PlaceholderNameAndValue>(),
|
||||||
|
new ReRouteBuilder()
|
||||||
|
.WithDownstreamReRoute(downstreamReRoute)
|
||||||
|
.Build());
|
||||||
|
|
||||||
|
var config = new ServiceProviderConfigurationBuilder()
|
||||||
|
.WithServiceDiscoveryProviderType("ServiceFabric")
|
||||||
|
.WithServiceDiscoveryProviderHost("localhost")
|
||||||
|
.WithServiceDiscoveryProviderPort(19081)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
this.Given(x => x.GivenTheDownStreamRouteIs(downstreamRoute))
|
||||||
|
.And(x => GivenTheServiceProviderConfigIs(config))
|
||||||
|
.And(x => x.GivenTheDownstreamRequestUriIs("http://localhost:19081?PartitionKind=test&PartitionKey=1"))
|
||||||
|
.And(x => x.GivenTheUrlReplacerWillReturn("/api/products/1"))
|
||||||
|
.When(x => x.WhenICallTheMiddleware())
|
||||||
|
.Then(x => x.ThenTheDownstreamRequestUriIs("http://localhost:19081/Ocelot/OcelotApp/api/products/1?PartitionKind=test&PartitionKey=1"))
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
private void GivenTheServiceProviderConfigIs(ServiceProviderConfiguration config)
|
private void GivenTheServiceProviderConfigIs(ServiceProviderConfiguration config)
|
||||||
{
|
{
|
||||||
_downstreamContext.ServiceProviderConfiguration = config;
|
_downstreamContext.ServiceProviderConfiguration = config;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user