How to add message header to the request when using default client of Azure service fabric?

前端 未结 2 1765
无人共我
无人共我 2020-11-30 10:24

I am wondering it is possible to inject custom message header to outgoing request to carry additional information without deserialize the payload to fullfill the functionali

相关标签:
2条回答
  • 2020-11-30 10:58

    I asked the same question on the MSDN forum a few weeks ago, however I didn't get a response there.

    I looked into the source code of the client library and haven't found a way to add headers. I'm afraid the only way is to add them as part of the method call. This could be done by using request-classes as method parameters and by using inheritance for them. (e.g. RequestBase class with headers [Authorization, ClientInfo, ...]). You then have to make sure these headers are set for every request by wrapping all invocations or by setting it manually.

    Further clarification from the Service Fabric team would be greatly appreciated.

    0 讨论(0)
  • 2020-11-30 11:04

    Update

    With SDK v2 you can now (relatively) easily modify the headers of both Reliable Services and Actors. Note in the examples below some wrapper members were omitted for brevity.

    Client

    We use ServiceProxyFactory to create proxies instead of the static ServiceProxy. Then we can wrap IServiceRemotingClientFactory and IServiceRemotingClient and intercept the service calls. The same can be done with ActorProxyFactory. Note this overrides the behavior of attributes such as the WcfServiceRemotingProviderAttribute, since we explicitly specify the client factory ourselves.

    _proxyFactory = new ServiceProxyFactory(c => new ServiceRemotingClientFactoryWrapper(
     // we can use any factory here
     new WcfServiceRemotingClientFactory(callbackClient: c)));
    
        private class ServiceRemotingClientFactoryWrapper : IServiceRemotingClientFactory
        {
            private readonly IServiceRemotingClientFactory _inner;
    
            public ServiceRemotingClientFactoryWrapper(IServiceRemotingClientFactory inner)
            {
                _inner = inner;
            }
    
            public async Task<IServiceRemotingClient> GetClientAsync(Uri serviceUri, ServicePartitionKey partitionKey, TargetReplicaSelector targetReplicaSelector,
                string listenerName, OperationRetrySettings retrySettings, CancellationToken cancellationToken)
            {
                var client = await _inner.GetClientAsync(serviceUri, partitionKey, targetReplicaSelector, listenerName, retrySettings, cancellationToken).ConfigureAwait(false);
                return new ServiceRemotingClientWrapper(client);
            }
        }
    
        private class ServiceRemotingClientWrapper : IServiceRemotingClient
        {
            private readonly IServiceRemotingClient _inner;
    
            public ServiceRemotingClientWrapper(IServiceRemotingClient inner)
            {
                _inner = inner;
            }
    
            public Task<byte[]> RequestResponseAsync(ServiceRemotingMessageHeaders messageHeaders, byte[] requestBody)
            {
                // use messageHeaders.AddHeader() here
                return _inner.RequestResponseAsync(messageHeaders, requestBody);
            }
    
            public void SendOneWay(ServiceRemotingMessageHeaders messageHeaders, byte[] requestBody)
            {
                // use messageHeaders.AddHeader() here
                _inner.SendOneWay(messageHeaders, requestBody);
            }
        }
    

    Server

    Inherit from ServiceRemotingDispatcher and ActorServiceRemotingDispatcher to examine the headers.

    class CustomServiceRemotingDispatcher : ServiceRemotingDispatcher
    {
        public override async Task<byte[]> RequestResponseAsync(IServiceRemotingRequestContext requestContext, ServiceRemotingMessageHeaders messageHeaders, byte[] requestBody)
        {
            // read messageHeaders here
            // or alternatively put them in an AsyncLocal<T> scope
            // so they can be accessed down the call chain
            return base.RequestResponseAsync(requestContext, messageHeaders, requestBody);
        }
    }
    

    To use this class, again we need to override the ServiceRemotingProviderAttribute by directly creating the communication listener:

    class MyService : StatelessService
    {
         protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
         {
              yield return new ServiceInstanceListener(context => new WcfServiceRemotingListener(context, new CustomServiceRemotingDispatcher());
         }
    }
    
    0 讨论(0)
提交回复
热议问题