如何在使用Azure服务织布默认客户端时向请求中添加消息头?

14

我想知道是否能够注入自定义的消息头到出站请求中,以携带额外的信息,而无需反序列化有效载荷来实现类似WCF提供的消息检查器的身份验证、验证或请求关联等功能?


我创建了一个NuGet包,你可以轻松地将其添加到你的项目中,以添加自定义标头和消息拦截。如果你想查看代码,它是公开可用的。 - Peter Bons
2个回答

21

更新

在SDK v2中,您现在可以(相对容易地)修改可靠服务和演员的标头。请注意,在下面的示例中,为了简洁起见,一些包装器成员被省略。

客户端

我们使用ServiceProxyFactory来创建代理,而不是静态的ServiceProxy。然后,我们可以包装IServiceRemotingClientFactoryIServiceRemotingClient并拦截服务调用。同样的方法也可以用于ActorProxyFactory。请注意,这会覆盖诸如WcfServiceRemotingProviderAttribute之类的属性的行为,因为我们明确指定了客户端工厂。

_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);
        }
    }

服务器

继承自ServiceRemotingDispatcherActorServiceRemotingDispatcher以检查标题。

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);
    }
}
为了使用这个类,我们需要再次覆盖ServiceRemotingProviderAttribute,通过直接创建通信侦听器来实现:
class MyService : StatelessService
{
     protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
     {
          yield return new ServiceInstanceListener(context => new WcfServiceRemotingListener(context, new CustomServiceRemotingDispatcher());
     }
}

我正在朝着同一个方向前进,你的代码示例确实帮了很多忙。但我仍然希望微软能够提供相同的消息处理机制,以便启用这样的用例。 - Xiangdong
ServiceInstanceListener没有像WcfServiceRemotingListener一样的构造函数参数来处理调度程序。在使用Remoting时,如何添加调度程序? - SondreB
问题在于ServiceInstanceListener需要传入ICommunicationListener而不是IServiceRemotingMessageHandler,并且该接口没有返回消息头的方法。 - SondreB
ServiceInstanceListener 中,您创建了一个通信侦听器,所有远程通信侦听器(如 WcfServiceRemotingListener)都接受消息处理程序作为构造函数参数。我已经使这段代码工作。请确保使用最新的 (v2) SDK。 - Eli Arbel
我尝试实现这个,但是我得到了这个错误:"提供的URI方案'localhost'无效;预期为'net.tcp'。" 我是这样创建代理的: return proxyFactory.CreateServiceProxy<IMyInterface>( new Uri("fabric:/myapp/myserviceService"), new ServicePartitionKey(0)); - Per
我写了一篇博客来总结EIi在这里阐述的内容。链接希望能有所帮助。 - Xiangdong

0

我几周前在MSDN论坛上提出了同样的问题,但是那里没有得到回复。

我查看了客户端库的源代码,没有找到添加标头的方法。恐怕唯一的方法是将它们作为方法调用的一部分添加。这可以通过使用请求类作为方法参数并使用继承来完成(例如,具有标头[授权、客户端信息等]的RequestBase类)。然后,您必须确保这些标头对每个请求都设置好,可以通过包装所有调用或手动设置来实现。

非常希望Service Fabric团队能够进一步澄清。


你在哪里找到客户端源代码的?我检查了API,发现有一个ServiceRemotingHeaders类,这让我想到可以添加自定义标头到发送请求中。此外,客户端似乎使用WCF进行通信。如果是这样,那么将消息检查器暴露给开发人员应该是可行的。 - Xiangdong
@Xiangdong 我用ILSpy查看了Microsoft.ServiceFabric.Services.dll。ServiceRemotingHeaders似乎是正确的方法,不是吗?然而,我还没有找到从外部设置它们的方法。我认为ServiceProxy.InvokeAsync()是发起请求的地方,它会在内部创建ServiceRemotingMessageHeaders变量并将其传递给下游ServicePartitionClient。但也许我错过了什么... - Christian Weiss

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接