All Projects → Expecho → ServiceFabric-Remoting-CustomHeaders

Expecho / ServiceFabric-Remoting-CustomHeaders

Licence: MIT license
This package allows injecting custom message headers into remoting messages (Actors and Reliable Services, V2 remoting only) at runtime. The headers are available client side to read. It also provides message interception using BeforeHandleRequestResponseAsync and AfterHandleRequestResponseAsync to act on remoting events.

Programming Languages

C#
18002 projects
powershell
5483 projects

Projects that are alternatives of or similar to ServiceFabric-Remoting-CustomHeaders

traefik-on-service-fabric
Azure Service Fabric now has support for Traefik!
Stars: ✭ 51 (+325%)
Mutual labels:  azure-service-fabric, service-fabric
service-fabric-queryable
Enable query support for your stateful services in Service Fabric via the OData protocol.
Stars: ✭ 42 (+250%)
Mutual labels:  reliable-stateful-service
CollectServiceFabricData
Service Fabric support utility to collect detailed cluster traces and other diagnostics data for ingestion into LogAnalytics workspace or an Azure Data Explorer instance for analysis.
Stars: ✭ 14 (+16.67%)
Mutual labels:  service-fabric
FabricSSO
A SSO(Single Sign On) platform with Microservices architecture built on IdentityServer 4
Stars: ✭ 14 (+16.67%)
Mutual labels:  service-fabric
service-fabric-explorer
Service Fabric Explorer is a web based dashboard for visualizing the state of a Service Fabric cluster.
Stars: ✭ 102 (+750%)
Mutual labels:  service-fabric
GenuineChannels
Collection of custom .NET Remoting channels
Stars: ✭ 29 (+141.67%)
Mutual labels:  remoting
pluralsight-using-azureservicefabric-in-production
No description or website provided.
Stars: ✭ 18 (+50%)
Mutual labels:  service-fabric
service-fabric-cli
Service Fabric CLI Tools
Stars: ✭ 50 (+316.67%)
Mutual labels:  azure-service-fabric
Temporal
Temporal service
Stars: ✭ 3,212 (+26666.67%)
Mutual labels:  service-fabric
Cadence
Cadence is a distributed, scalable, durable, and highly available orchestration engine to execute asynchronous long-running business logic in a scalable and resilient way.
Stars: ✭ 5,522 (+45916.67%)
Mutual labels:  service-fabric
microservices
Education & lessons learned from the field. Mainly focusing on AKS and Containers.
Stars: ✭ 16 (+33.33%)
Mutual labels:  service-fabric
powershell-electron-demo
A PowerShell and Electron Demo
Stars: ✭ 49 (+308.33%)
Mutual labels:  remoting
quacktors
The quacking awesome Go actor model framework!
Stars: ✭ 14 (+16.67%)
Mutual labels:  remoting
CoreRemoting
RPC library with classic .NET Remoting flavour
Stars: ✭ 23 (+91.67%)
Mutual labels:  remoting

ServiceFabric.Remoting.CustomHeaders

This package allows injecting custom headers into remoting messages (Actors and Reliable Services, V2 remoting only) at runtime. The headers are available client side to read. It also provides message interception using BeforeHandleRequestResponseAsync and AfterHandleRequestResponseAsync to act on remoting events.

Common used classes:

NuGet

Download the NuGet package NuGet Status

Examples

This repository includes a Service Fabric application for demonstration purposes. A Console Application is used to access the application and shows the usage of the package.

Usage scenarios

Custom headers can be used to pass data between the sender and the receiver like tracing information or security context data. Using the BeforeHandleRequestResponseAsync and AfterHandleRequestResponseAsync actions additional logging can be applied monitor the flow between remoting calls.

How to use

Prepare Reliable Services

Modify the service and create a listener that can handle the requests

protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
    yield return new ServiceInstanceListener(context =>
        new FabricTransportServiceRemotingListener(context,
            new ExtendedServiceRemotingMessageDispatcher(context, this)));
}

Prepare Actors

Register the actor using the ExtendedActorService service (usually done in the program.cs file):

ActorRuntime.RegisterActorAsync<DemoActor> (
(context, actorType) =>
   {
	   return new ExtendedActorService(context, actorType);
   }).GetAwaiter().GetResult();

Sender

On the sender side, create a proxy to the actor or service. The Create method accepts an instance of the CustomHeaders class:

Calling Reliable Services

var customHeaders = new CustomHeaders
{
	{"Header1", DateTime.Now},
	{"Header2", Guid.NewGuid()}
};

var serviceUri = new Uri("fabric:/ServiceFabric.Remoting.CustomHeaders.DemoApplication/DemoService");
var proxyFactory = new ServiceProxyFactory(handler => 
                    new ExtendedServiceRemotingClientFactory(
                        new FabricTransportServiceRemotingClientFactory(remotingCallbackMessageHandler: handler), customHeaders));
var proxy = proxyFactory.CreateServiceProxy<IDemoService>(serviceUri); // or  in case of actors
var actorResponse = proxy.SayHelloToActor().GetAwaiter().GetResult();

Sending Message to Actors

var customHeaders = new CustomHeaders
{
	{"Header1", DateTime.Now},
	{"Header2", Guid.NewGuid()}
};

var serviceUri = new Uri("fabric:/ServiceFabric.Remoting.CustomHeaders.DemoApplication/DemoService");
var proxyFactory = new ActorProxyFactory(handler => 
                    new ExtendedServiceRemotingClientFactory(
		        new FabricTransportActorRemotingClientFactory(handler), customHeaders));
var proxy = proxyFactory.CreateActorProxy<IDemoService>(serviceUri); 
var response = proxy.SayHello().GetAwaiter().GetResult();

There is an overload of the Create method that accepts a Func<CustomHeaders>. This is useful in scenarios where the created proxy factory or proxy is reused. Since creating a proxy factory is expensive this is the preferred way if you need dynamic header values. The func is invoked on every request made using the proxy:

var customHeadersProvider = new Func<CustomHeaders>(() => new CustomHeaders
{
	{"Header1", DateTime.Now},
	{"Header2", Guid.NewGuid()}
});
var serviceUri = new Uri("fabric:/ServiceFabric.Remoting.CustomHeaders.DemoApplication/DemoService");
var proxyFactory = new ServiceProxyFactory(handler =>
                    new ExtendedServiceRemotingClientFactory(
                        new FabricTransportServiceRemotingClientFactory(remotingCallbackMessageHandler: handler), customHeadersProvider));
var proxy = proxyFactory.CreateServiceProxy<IDemoService>(serviceUri);

Receiver

The receiving service or actor can extract the values in the custom headers using the RemotingContext class:

public async Task<string> SayHello()
{
	var remotingContext =
		string.Join(", ", RemotingContext.Keys.Select(k => $"{k}: {RemotingContext.GetData(k)}"));

	ServiceEventSource.Current.ServiceMessage(Context, $"SayHelloToActor got context: {remotingContext}");
	return Task.FromResult($"Got the following message headers: {remotingContext}")
}

Sample content of remotingContext:

Header1: 06/24/2018 08:30:18, Header2: 2c95548a-6efd-4855-82eb-29ea827be87b

Headers passthrough

In case the headers need to flow from one call to the other CustomHeaders.FromRemotingContext can be used as demonstrated:

public async Task<string> SayHelloToActor()
{
	var remotingContext =
		string.Join(", ", RemotingContext.Keys.Select(k => $"{k}: {RemotingContext.GetData(k)}"));

	ServiceEventSource.Current.ServiceMessage(Context, $"SayHelloToActor got context: {remotingContext}");
	var proxyFactory = new ActorProxyFactory(handler =>
                new ExtendedServiceRemotingClientFactory(
                    new FabricTransportActorRemotingClientFactory(handler), CustomHeaders.FromRemotingContext));
	var proxy = proxyFactory.CreateActorProxy<IDemoActor>(new ActorId(1));
	var response = await proxy.GetGreetingResponseAsync(CancellationToken.None);

	return $"DemoService passed context '{remotingContext}' to actor and got as response: {response}";
}

This removes the need to create a new CustomHeaders instance based on the current values in the RemotingContext.

Message interception

Messages can be intercepted on both the sending side and the receiving side. This can be used fo example to log method calls or performance.

Client-side message interception

On the receiving side messages can be intercepted using the BeforeHandleRequestResponseAsync and AfterHandleRequestResponseAsync extension points when creating a service listener:

For services

protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
	yield return new ServiceInstanceListener(context =>
		new FabricTransportServiceRemotingListener(context,
			new ExtendedServiceRemotingMessageDispatcher(context, this)
			{
				// Optional, log the call before being handled
				BeforeHandleRequestResponseAsync = requestInfo =>
				{
					var sw = new Stopwatch();
					sw.Start();
					ServiceEventSource.Current.ServiceMessage(Context, $"BeforeHandleRequestResponseAsync {requestInfo.Service} {requestInfo.Method}");
					return Task.FromResult<object>(sw);
				},
				// Optional, log the call after being handled
				AfterHandleRequestResponseAsync = responseInfo =>
				{
					var sw = (Stopwatch) responseInfo.State;
					ServiceEventSource.Current.ServiceMessage(Context, $"AfterHandleRequestResponseAsync {responseInfo.Service} {responseInfo.Method} took {sw.ElapsedMilliseconds}ms");
					return Task.CompletedTask;
				}
			}));
}

For actors

ActorRuntime.RegisterActorAsync<DemoActor> (
(context, actorType) =>
   {
	   var service = new ExtendedActorService(context, actorType)
	   {
		   // Optional, allows call interception. Executed before the response is handled
		   BeforeHandleRequestResponseAsync = requestInfo =>
		   {
			   ActorEventSource.Current.Message($"BeforeHandleRequestResponseAsync {requestInfo.ActorService} {requestInfo.Method} for actor {requestInfo.ActorId.ToString()}");
			   return Task.CompletedTask;
		   },
		   // Optional, allows call interception. Executed after the response is handled
		   AfterHandleRequestResponseAsync = responseInfo =>
		   {
			   ActorEventSource.Current.Message($"AfterHandleRequestResponseAsync {responseInfo.ActorService} {responseInfo.Method} for actor {responseInfo.ActorId.ToString()}");
			   return Task.CompletedTask;
		   }
	   };
	   return service;
   }).GetAwaiter().GetResult();

Server-side message interception

On the sending side messages can be intercepted using the BeforeSendRequestResponseAsync and AfterSendRequestResponseAsync extension points when creating the ExtendedServiceRemotingClientFactory on constructor of the ServiceProxyFactory:

var proxyFactory = new ServiceProxyFactory(handler => // or ActorProxyFactory in case of actors
        new ExtendedServiceRemotingClientFactory(
            new FabricTransportServiceRemotingClientFactory(remotingCallbackMessageHandler: handler), customHeadersProvider)
        {
            // Optional, log the call before being handled
            BeforeSendRequestResponseAsync = requestInfo =>
            {
                var sw = new Stopwatch();
                sw.Start();
                Console.WriteLine($"BeforeSendRequestResponseAsync {requestInfo.Method}");
                return Task.FromResult<object>(sw);
            },
            // Optional, log the call after being handled
            AfterSendRequestResponseAsync = responseInfo =>
            {
                var sw = (Stopwatch)responseInfo.State;
                Console.WriteLine($"AfterSendRequestResponseAsync {responseInfo.Method} took {sw.ElapsedMilliseconds}ms");
                return Task.CompletedTask;
            }
        });
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].