-
Notifications
You must be signed in to change notification settings - Fork 18
HTTP Gateway
The package C3.ServiceFabric.HttpServiceGateway
contains the actual gateway. It uses the package C3.ServiceFabric.HttpCommunication
for the communication with the services. Please look at the corresponding document in this wiki to learn more about it. It is important to understand that package if you want to change the options related to the communication.
The gateway is implemented as an ASP.NET Core middleware called HttpServiceGatewayMiddleware
.
The gateway has the following features:
The Service Fabric SDK contains classes for resolving services which use one of the built-in communication channels. (ServiceProxy
, ActorProxy
, WcfCommunicationClientFactory
).
However if your services use HTTP you have to manually resolve the endpoint by using the lower-level classes like ServicePartitionResolver
.
The gateway contains an HTTP implementation of ICommunicationClientFactory
for resolving HTTP-based services. (see C3.ServiceFabric.HttpCommunication
for details)
The classes ServiceProxy
and ActorProxy
from the SDK implement transparent retry logic in case of failures (e.g. because a node went down or the service returned a timeout). If you are using HTTP, you are on your own again.
This gateway implements the retry functionality of ICommunicationClientFactory
for HTTP. (see C3.ServiceFabric.HttpCommunication
for details)
After the target service address was resolved, the incoming request is forwarded to the target service by copying all request headers and the request body. (see HttpServiceGatewayMiddleware
for details)
Since this project is implemented as an ASP.NET Core middleware, you can use the IApplicationBuilder.Map()
feature to bind services to different paths of your gateway. You can e.g. map "/service1" to "InternalService1" and "/service2" to "InternalService2". (see samples/HttpGateway/Startup.cs
for details)
You can also use this feature to integrate the middleware into an existing application.
Since your original client now no longer talks directly to the target service, the target service doesn't get the original IP address of the client and it also doesn't know about the original URL which was requested by the client.
For this reason, the gateway adds standard proxy headers to pass this information to the target services. It implements the new "Forwarded" HTTP header and the non-standard headers X-Forwarded-For
, X-Forwarded-Host
, X-Forwarded-Proto
.
It also sets a custom header called X-Forwarded-PathBase
which contains the segment of the path under which the gateway hosts the service (e.g. "/service1").
This way, services can adjust their absolute URLs accordingly. See this page for an example.
There is a sample project calledsamples/HttpGateway
that shows how to use this library.
The package is available on NuGet: C3.ServiceFabric.HttpServiceGateway
.
This package relies on C3.ServiceFabric.HttpCommunication
which must be configured in your Startup.ConfigureServices()
method. Please look at the document HTTP Communication for a detailed explanation.
If you want to use the HttpCommunicationClient with the default options, just add the following snippet to your ConfigureServices()
method:
services.AddServiceFabricHttpCommunication();
Retry behavior, timeouts and so on are configured through the HttpCommunicationOptions
-class. Please look at the wiki page HTTP Communication for details.
If you want to configure each service through code or if you need maximum flexibility, you can configure the gateway middleware through the class HttpServiceGatewayOptions
, which has the following properties:
-
ServiceName
: Name of the service within Service Fabric. (e.g.fabric:/MyApp/MyService
) -
ListenerName
: This property must be used to set the HTTP endpoint name if the ServiceManifest.xml contains multiple endpoints. If the service only contains one endpoint, this property is optional. -
ServicePartitionKeyResolver
: Delegate for resolving the partition key for partitioned services.
The gateway middleware can be added to your request pipeline by calling one of the RunHttpServiceGateway
extension methods on IApplicationBuilder
in your Startup.Configure()
-method:
// this would forward every request to the service. this way, your application can only handle one service.
app.RunHttpServiceGateway("fabric:/GatewaySample/HttpService");
// ... this only forwards requests on a certain path. This is the simplest case for non-partitioned services.
app.RunHttpServiceGateway("/service1", "fabric:/GatewaySample/HttpService");
// ... pass an instance of HttpServiceGatewayOptions for more options (e.g. to define the ServicePartitionKeyResolver)
app.RunHttpServiceGateway("/service", new HttpServiceGatewayOptions
{
ServiceName = new Uri("fabric:/GatewaySample/HttpService"),
ServicePartitionKeyResolver = (context) =>
{
string namedPartitionKey = context.Request.Query["partitionKey"];
return new ServicePartitionKey(namedPartitionKey);
}
});
// ... if you need to do multiple things within the path branch, you can use app.Map():
app.Map("/service", appBuilder =>
{
appBuilder.RunHttpServiceGateway(new HttpServiceGatewayOptions
{
ServiceName = new Uri("fabric:/GatewaySample/HttpService")
});
});
The gateway can also be configured through a Microsoft.Extensions.Configuration
-based mechanism. This allows you to read the configuration for multiple services from e.g. a file.
This mechanism offers the following configuration options for each service:
-
PathMatch
: The path on the gateway that should be used for forwarding requests to the service. -
ServiceName
: Name of the service within Service Fabric. (e.g.fabric:/MyApp/MyService
) -
ListenerName
: This property must be used to set the HTTP endpoint name if the ServiceManifest.xml contains multiple endpoints. If the service only contains one endpoint, this property is optional.
Note that this mechanism doesn't allow you to specify a ServicePartitionKeyResolver
since this must be a delegate. If you need this, use the RunHttpServiceGateway
extension methods.
An example JSON-file for this IConfiguration-based setup would be:
{
"GatewayServices": [
{
"PathMatch": "/some-service1",
"ServiceName": "fabric:/MyApp/SomeService1"
},
{
"PathMatch": "/some-service2",
"ServiceName": "fabric:/MyApp/SomeService2",
"ListenerName": "OwinListener"
}
]
}
In this case, the gateway middleware can be added to your request pipeline by calling one of the RunHttpServiceGateways
extension methods on IApplicationBuilder
in your Startup.Configure()
-method:
// this configures one or many gateway instances based on the Configuration system (e.g. file-based).
app.RunHttpServiceGateways(Configuration.GetSection("GatewayServices"));
// this configures one or many gateway instances based on a list of configuration entries.
var services = new List<HttpServiceGatewayConfigurationEntry>
{
new HttpServiceGatewayConfigurationEntry("/another-service1", "fabric:/MyApp/AnotherService1"),
new HttpServiceGatewayConfigurationEntry("/another-service2", "fabric:/MyApp/AnotherService2", "OwinListener")
};
app.RunHttpServiceGateways(services);
Have a look at the HttpGateway-sample project for a working example of this library.