通过 Reliable Services 使用 C# 进行服务远程处理Service remoting in C# with Reliable Services

对于不依赖于特定通信协议或堆栈的服务,如 Web API、Windows Communication Foundation 或其他服务,Reliable Services 框架提供一种远程处理机制,用于快速而轻松地为服务设置远程过程调用。For services that aren't tied to a particular communication protocol or stack, such as a web API, Windows Communication Foundation, or others, the Reliable Services framework provides a remoting mechanism to quickly and easily set up remote procedure calls for services. 本文讨论了如何为使用 C# 编写的服务设置远程过程调用。This article discusses how to set up remote procedure calls for services written with C#.

为服务设置远程处理Set up remoting on a service

可以通过两个简单的步骤为服务设置远程处理:You can set up remoting for a service in two simple steps:

  1. 为服务创建要实现的接口。Create an interface for your service to implement. 此接口定义可供服务的远程过程调用使用的方法。This interface defines the methods that are available for a remote procedure call on your service. 这些方法必须是返回任务的异步方法。The methods must be task-returning asynchronous methods. 接口必须实现 Microsoft.ServiceFabric.Services.Remoting.IService 以表明此服务具有远程处理接口。The interface must implement Microsoft.ServiceFabric.Services.Remoting.IService to signal that the service has a remoting interface.
  2. 在服务中使用远程处理侦听器。Use a remoting listener in your service. 远程处理侦听器是可以提供远程处理功能的 ICommunicationListener 实现。A remoting listener is an ICommunicationListener implementation that provides remoting capabilities. Microsoft.ServiceFabric.Services.Remoting.Runtime 命名空间包含一个同时适用于无状态服务和有状态服务的扩展方法 CreateServiceRemotingInstanceListeners,可用于创建使用默认远程处理传输协议的远程处理侦听器。The Microsoft.ServiceFabric.Services.Remoting.Runtime namespace contains the extension method CreateServiceRemotingInstanceListeners for both stateless and stateful services that can be used to create a remoting listener by using the default remoting transport protocol.

备注

Remoting 命名空间可用作名为 Microsoft.ServiceFabric.Services.Remoting 的单独 NuGet 包。The Remoting namespace is available as a separate NuGet package called Microsoft.ServiceFabric.Services.Remoting.

例如,以下无状态服务公开了一个方法,此方法通过远程过程调用获取“Hello World”。For example, the following stateless service exposes a single method to get "Hello World" over a remote procedure call.

using Microsoft.ServiceFabric.Services.Communication.Runtime;
using Microsoft.ServiceFabric.Services.Remoting;
using Microsoft.ServiceFabric.Services.Remoting.Runtime;
using Microsoft.ServiceFabric.Services.Runtime;

public interface IMyService : IService
{
    Task<string> HelloWorldAsync();
}

class MyService : StatelessService, IMyService
{
    public MyService(StatelessServiceContext context)
        : base (context)
    {
    }

    public Task<string> HelloWorldAsync()
    {
        return Task.FromResult("Hello!");
    }

    protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
    {
     return this.CreateServiceRemotingInstanceListeners();
    }
}

备注

服务接口中的参数和返回类型可以是任何简单、复杂或自定义的类型,但它们必须是可以通过 .NET DataContractSerializer 序列化的类型。The arguments and the return types in the service interface can be any simple, complex, or custom types, but they must be able to be serialized by the .NET DataContractSerializer.

调用远程服务的方法Call remote service methods

若要使用远程处理堆栈在服务上调用方法,可以通过 Microsoft.ServiceFabric.Services.Remoting.Client.ServiceProxy 类对此服务使用本地代理。Calling methods on a service by using the remoting stack is done by using a local proxy to the service through the Microsoft.ServiceFabric.Services.Remoting.Client.ServiceProxy class. ServiceProxy 方法通过使用此服务实现的相同接口来创建本地代理。The ServiceProxy method creates a local proxy by using the same interface that the service implements. 使用此代理,可在此接口上远程调用方法。With that proxy, you can call methods on the interface remotely.


IMyService helloWorldClient = ServiceProxy.Create<IMyService>(new Uri("fabric:/MyApplication/MyHelloWorldService"));

string message = await helloWorldClient.HelloWorldAsync();

此远程处理框架将服务引发的异常传播到客户端。The remoting framework propagates exceptions thrown by the service to the client. 因此,使用 ServiceProxy 时,客户端负责处理服务引起的异常。As a result, when ServiceProxyis used, the client is responsible for handling the exceptions thrown by the service.

服务代理生存期Service proxy lifetime

由于创建服务代理是轻量型操作,因此可根据需求随意创建,数目不限。Service proxy creation is a lightweight operation, so you can create as many as you need. 如有需要,可重复使用服务代理实例。Service proxy instances can be reused for as long as they are needed. 如果远程过程调用引发了异常,仍可以重复使用相同的代理实例。If a remote procedure call throws an exception, you can still reuse the same proxy instance. 每个服务代理都包含用于通过线路发送消息的通信客户端。Each service proxy contains a communication client used to send messages over the wire. 进行远程调用时,会在内部执行检查,以确认通信客户端是否有效。While invoking remote calls, internal checks are performed to determine if the communication client is valid. 可以根据这些检查的结果,视需要重新创建通信客户端。Based on the results of those checks, the communication client is re-created if needed. 因此,如果发生异常,无需重新创建 ServiceProxyTherefore, if an exception occurs, you do not need to re-create ServiceProxy.

服务代理工厂生存期Service proxy factory lifetime

ServiceProxyFactory 是为不同远程接口创建代理实例的工厂。ServiceProxyFactory is a factory that creates proxy instances for different remoting interfaces. 如果使用 API ServiceProxyFactory.CreateServiceProxy 来创建代理,则框架会创建单一实例服务代理。If you use the API ServiceProxyFactory.CreateServiceProxy to create a proxy, the framework creates a singleton service proxy. 在需要替代 IServiceRemotingClientFactory 属性时,手动创建一个 ServiceProxyFactory 是有用的。It is useful to create one manually when you need to override IServiceRemotingClientFactory properties. 工厂创建是一项代价高昂的操作。Factory creation is an expensive operation. 服务代理工厂维护通信客户端的内部缓存。A service proxy factory maintains an internal cache of the communication client. 最佳做法是尽可能久地缓存服务代理工厂。A best practice is to cache the service proxy factory for as long as possible.

远程异常处理Remoting exception handling

服务 API 引发的所有远程异常都将作为 AggregateException 发送回客户端。All remote exceptions thrown by the service API are sent back to the client as AggregateException. 远程异常应该可以通过 DataContract 来序列化。Remote exceptions should be able to be serialized by DataContract. 否则,代理 API 会引发 ServiceException,其中包含序列化错误。If they are not, the proxy API throws ServiceException with the serialization error in it.

对于创建服务代理时所使用的服务分区,服务代理会处理其所有的故障转移异常。The service proxy handles all failover exceptions for the service partition it is created for. 如果存在故障转移异常(非暂时异常),它将重新解析终结点,并通过正确的终结点重试调用。It re-resolves the endpoints if there are failover exceptions (non-transient exceptions) and retries the call with the correct endpoint. 故障转移异常的重试次数无限。The number of retries for failover exceptions is indefinite. 如果发生暂时性异常,代理会重试调用。If transient exceptions occur, the proxy retries the call.

默认重试参数由 OperationRetrySettings 提供。Default retry parameters are provided by OperationRetrySettings.

用户可以通过将 OperationRetrySettings 对象传递给 ServiceProxyFactory 构造函数来配置这些值。A user can configure these values by passing the OperationRetrySettings object to the ServiceProxyFactory constructor.

使用远程处理 V2 堆栈Use the remoting V2 stack

从 NuGet 远程处理包版本 2.8 开始,可以通过相应的选项来使用远程处理 V2 堆栈。As of version 2.8 of the NuGet remoting package, you have the option to use the remoting V2 stack. 远程处理 V2 堆栈性能更好,The remoting V2 stack performs better. 并提供自定义序列化等功能和更多的可插入 API。It also provides features like custom serialization and more pluggable APIs. 模板代码使用的仍然是远程处理 V1 堆栈。Template code continues to use the remoting V1 stack. 远程处理 V2 与 V1(以前的远程处理堆栈)不兼容,Remoting V2 is not compatible with V1 (the previous remoting stack). 请按从 V1 升级到 V2 一文中的说明操作,避免影响服务可用性。Follow the instructions in the article Upgrade from V1 to V2 to avoid effects on service availability.

以下方法可用来启用 V2 堆栈。The following approaches are available to enable the V2 stack.

通过程序集属性使用 V2 堆栈Use an assembly attribute to use the V2 stack

以下步骤使用一个程序集属性将模板代码更改为使用 V2 堆栈。These steps change the template code to use the V2 stack by using an assembly attribute.

  1. 在服务清单中将终结点资源从 "ServiceEndpoint" 更改为 "ServiceEndpointV2"Change the endpoint resource from "ServiceEndpoint" to "ServiceEndpointV2" in the service manifest.

    <Resources>
        <Endpoints>
          <Endpoint Name="ServiceEndpointV2" />
        </Endpoints>
    </Resources>
    
  2. 使用 Microsoft.ServiceFabric.Services.Remoting.Runtime.CreateServiceRemotingInstanceListeners 扩展方法创建远程处理侦听器(对于 V1 和 V2 是相同的)。Use the Microsoft.ServiceFabric.Services.Remoting.Runtime.CreateServiceRemotingInstanceListeners extension method to create remoting listeners (equal for both V1 and V2).

    protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
    {
        return this.CreateServiceRemotingInstanceListeners();
    }
    
  3. 使用 FabricTransportServiceRemotingProvider 属性来标记包含远程处理接口的程序集。Mark the assembly that contains the remoting interfaces with a FabricTransportServiceRemotingProvider attribute.

    [assembly: FabricTransportServiceRemotingProvider(RemotingListenerVersion = RemotingListenerVersion.V2, RemotingClientVersion = RemotingClientVersion.V2)]
    

不需要在客户端项目中更改代码。No code changes are required in the client project. 使用接口程序集生成客户端程序集,以确保使用前面显示的程序集属性。Build the client assembly with the interface assembly to make sure that the assembly attribute previously shown is used.

通过显式 V2 类来使用 V2 堆栈Use explicit V2 classes to use the V2 stack

若要启用 V2 堆栈,还可以使用显式 V2 类,作为程序集属性的替代方法。As an alternative to using an assembly attribute, the V2 stack also can be enabled by using explicit V2 classes.

以下步骤使用显式 V2 类将模板代码更改为使用 V2 堆栈。These steps change the template code to use the V2 stack by using explicit V2 classes.

  1. 在服务清单中将终结点资源从 "ServiceEndpoint" 更改为 "ServiceEndpointV2"Change the endpoint resource from "ServiceEndpoint" to "ServiceEndpointV2" in the service manifest.

    <Resources>
        <Endpoints>
          <Endpoint Name="ServiceEndpointV2" />
        </Endpoints>
    </Resources>
    
  2. 使用 Microsoft.ServiceFabric.Services.Remoting.V2.FabricTransport.Runtime 命名空间中的 FabricTransportServiceRemotingListenerUse FabricTransportServiceRemotingListener from the Microsoft.ServiceFabric.Services.Remoting.V2.FabricTransport.Runtime namespace.

    protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
    {
        return new[]
        {
            new ServiceInstanceListener((c) =>
            {
                return new FabricTransportServiceRemotingListener(c, this);
    
            })
        };
    }
    
  3. 使用 Microsoft.ServiceFabric.Services.Remoting.V2.FabricTransport.Client 命名空间中的 FabricTransportServiceRemotingClientFactory 创建客户端。Use FabricTransportServiceRemotingClientFactory from the Microsoft.ServiceFabric.Services.Remoting.V2.FabricTransport.Client namespace to create clients.

    var proxyFactory = new ServiceProxyFactory((c) =>
          {
              return new FabricTransportServiceRemotingClientFactory();
          });
    

从远程处理 V1 升级到远程处理 V2Upgrade from remoting V1 to remoting V2

若要从 V1 升级到 V2,必须执行双步升级。To upgrade from V1 to V2, two-step upgrades are required. 请按以下顺序执行步骤。Follow the steps in this sequence.

  1. 使用以下属性将 V1 服务升级到 V2 服务。Upgrade the V1 service to V2 service by using this attribute. 此项更改可确保服务在 V1 和 V2 侦听器上侦听。This change makes sure that the service listens on the V1 and V2 listener.

    a.a. 在服务清单中添加名为“ServiceEndpointV2”的终结点资源。Add an endpoint resource with the name "ServiceEndpointV2" in the service manifest.

    <Resources>
      <Endpoints>
        <Endpoint Name="ServiceEndpointV2" />  
      </Endpoints>
    </Resources>
    

    b.b. 使用以下扩展方法创建远程处理侦听器。Use the following extension method to create a remoting listener.

    protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
    {
        return this.CreateServiceRemotingInstanceListeners();
    }
    

    c.c. 在远程处理接口上添加程序集属性,以使用 V1 和 V2 侦听器以及 V2 客户端。Add an assembly attribute on remoting interfaces to use the V1 and V2 listener and the V2 client.

    [assembly: FabricTransportServiceRemotingProvider(RemotingListenerVersion = RemotingListenerVersion.V2|RemotingListenerVersion.V1, RemotingClientVersion = RemotingClientVersion.V2)]
    
    
  2. 使用 V2 客户端属性将 V1 客户端升级到 V2 客户端。Upgrade the V1 client to a V2 client by using the V2 client attribute. 此步骤确保客户端使用 V2 堆栈。This step makes sure the client uses the V2 stack. 不需要在客户端项目/服务中进行更改。No change in the client project/service is required. 使用更新的接口程序集生成客户端项目便已足够。Building client projects with updated interface assembly is sufficient.

  3. 此步骤是可选的。This step is optional. 使用 V2 侦听器属性,然后升级 V2 服务。Use the V2 listener attribute, and then upgrade the V2 service. 此步骤确保服务仅在 V2 侦听器上侦听。This step makes sure that the service is listening only on the V2 listener.

    [assembly: FabricTransportServiceRemotingProvider(RemotingListenerVersion = RemotingListenerVersion.V2, RemotingClientVersion = RemotingClientVersion.V2)]
    

使用远程处理 V2(与接口兼容)堆栈Use the remoting V2 (interface compatible) stack

远程处理 V2(与接口兼容,又称 V2_1)堆栈具有 V2 远程处理堆栈的所有功能。The remoting V2 (interface compatible, known as V2_1) stack has all the features of the V2 remoting stack. 其接口堆栈与远程处理 V1 堆栈兼容,但不后向兼容 V2 和 V1。Its interface stack is compatible with the remoting V1 stack, but it is not backward compatible with V2 and V1. 若要从 V1 升级到 V2_1 且不影响服务可用性,请遵循“从 V1 升级到 V2(接口兼容)”一文中的步骤。To upgrade from V1 to V2_1 without affecting service availability, follow the steps in the article Upgrade from V1 to V2 (interface compatible).

通过程序集属性使用远程处理 V2(与接口兼容)堆栈Use an assembly attribute to use the remoting V2 (interface compatible) stack

按照以下步骤更改到 V2_1 堆栈。Follow these steps to change to a V2_1 stack.

  1. 在服务清单中添加名为“ServiceEndpointV2_1”的终结点资源。Add an endpoint resource with the name "ServiceEndpointV2_1" in the service manifest.

    <Resources>
      <Endpoints>
        <Endpoint Name="ServiceEndpointV2_1" />  
      </Endpoints>
    </Resources>
    
  2. 使用远程处理扩展方法创建远程处理侦听器。Use the remoting extension method to create a remoting listener.

    protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
    {
        return this.CreateServiceRemotingInstanceListeners();
    }
    
  3. 在远程处理接口上添加程序集属性Add an assembly attribute on remoting interfaces.

    [assembly:  FabricTransportServiceRemotingProvider(RemotingListenerVersion=  RemotingListenerVersion.V2_1, RemotingClientVersion= RemotingClientVersion.V2_1)]
    
    

不需要在客户端项目中进行更改。No changes are required in the client project. 使用接口程序集生成客户端程序集,以确保使用的是以前的程序集属性。Build the client assembly with the interface assembly to make sure that the previous assembly attribute is being used.

使用显式远程处理类为 V2(与接口兼容)版本创建侦听器/客户端工厂Use explicit remoting classes to create a listener/client factory for the V2 (interface compatible) version

执行以下步骤:Follow these steps:

  1. 在服务清单中添加名为“ServiceEndpointV2_1”的终结点资源。Add an endpoint resource with the name "ServiceEndpointV2_1" in the service manifest.

    <Resources>
      <Endpoints>
        <Endpoint Name="ServiceEndpointV2_1" />  
      </Endpoints>
    </Resources>
    
  2. 使用远程处理 V2 侦听器Use the remoting V2 listener. 使用的默认服务终结点资源名称为“ServiceEndpointV2_1”。The default service endpoint resource name used is "ServiceEndpointV2_1." 必须在服务清单中定义该名称。It must be defined in the service manifest.

    protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
    {
        return new[]
        {
            new ServiceInstanceListener((c) =>
            {
                var settings = new FabricTransportRemotingListenerSettings();
                settings.UseWrappedMessage = true;
                return new FabricTransportServiceRemotingListener(c, this,settings);
    
            })
        };
    }
    
  3. 使用 V2 客户端工厂Use the V2 client factory.

    var proxyFactory = new ServiceProxyFactory((c) =>
          {
            var settings = new FabricTransportRemotingSettings();
            settings.UseWrappedMessage = true;
            return new FabricTransportServiceRemotingClientFactory(settings);
          });
    

从远程处理 V1 升级到远程处理 V2(接口兼容)Upgrade from remoting V1 to remoting V2 (interface compatible)

若要从 V1 升级到 V2(与接口兼容,称为 V2_1),必须执行双步升级。To upgrade from V1 to V2 (interface compatible, known as V2_1), two-step upgrades are required. 请按以下顺序执行步骤。Follow the steps in this sequence.

备注

从 V1 升级到 V2 时,请确保更新 Remoting 命名空间以使用 V2。When upgrading from V1 to V2, ensure the Remoting namespace is updated to use V2. 示例:'Microsoft.ServiceFabric.Services.Remoting.V2.FabricTransport.Client`Example: 'Microsoft.ServiceFabric.Services.Remoting.V2.FabricTransport.Client`

  1. 使用以下属性将 V1 服务升级到 V2_1 服务。Upgrade the V1 service to V2_1 service by using the following attribute. 此项更改可确保服务在 V1 和 V2_1 侦听器上侦听。This change makes sure that the service is listening on the V1 and the V2_1 listener.

    a.a. 在服务清单中添加名为“ServiceEndpointV2_1”的终结点资源。Add an endpoint resource with the name "ServiceEndpointV2_1" in the service manifest.

    <Resources>
      <Endpoints>
        <Endpoint Name="ServiceEndpointV2_1" />  
      </Endpoints>
    </Resources>
    

    b.b. 使用以下扩展方法创建远程处理侦听器。Use the following extension method to create a remoting listener.

    protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
    {
        return this.CreateServiceRemotingInstanceListeners();
    }
    

    c.c. 在远程处理接口上添加程序集属性,以使用 V1、V2_1 侦听器和 V2_1 客户端。Add an assembly attribute on remoting interfaces to use the V1, V2_1 listener, and V2_1 client.

    [assembly: FabricTransportServiceRemotingProvider(RemotingListenerVersion = RemotingListenerVersion.V2_1 | RemotingListenerVersion.V1, RemotingClientVersion = RemotingClientVersion.V2_1)]
    
    
  2. 使用 V2_1 客户端属性将 V1 客户端升级到 V2_1 客户端。Upgrade the V1 client to the V2_1 client by using the V2_1 client attribute. 此步骤确保客户端使用 V2_1 堆栈。This step makes sure the client is using the V2_1 stack. 不需要在客户端项目/服务中进行更改。No change in the client project/service is required. 使用更新的接口程序集生成客户端项目便已足够。Building client projects with updated interface assembly is sufficient.

  3. 此步骤是可选的。This step is optional. 从属性中删除 V1 侦听器版本,然后升级 V2 服务。Remove the V1 listener version from the attribute, and then upgrade the V2 service. 此步骤确保服务仅在 V2 侦听器上侦听。This step makes sure that the service is listening only on the V2 listener.

    [assembly: FabricTransportServiceRemotingProvider(RemotingListenerVersion = RemotingListenerVersion.V2_1, RemotingClientVersion = RemotingClientVersion.V2_1)]
    

在远程处理包装消息中使用自定义序列化Use custom serialization with a remoting wrapped message

对于远程处理包装消息,我们会创建一个包装对象,并将所有参数作为其中的一个字段。For a remoting wrapped message, we create a single wrapped object with all the parameters as a field in it. 执行以下步骤:Follow these steps:

  1. 实现 IServiceRemotingMessageSerializationProvider 接口,以提供自定义序列化的实现。Implement the IServiceRemotingMessageSerializationProvider interface to provide implementation for custom serialization. 以下代码片段演示了具体如何实现。This code snippet shows what the implementation looks like.

    public class ServiceRemotingJsonSerializationProvider : IServiceRemotingMessageSerializationProvider
      {
        public IServiceRemotingMessageBodyFactory CreateMessageBodyFactory()
        {
          return new JsonMessageFactory();
        }
    
        public IServiceRemotingRequestMessageBodySerializer CreateRequestMessageSerializer(Type serviceInterfaceType, IEnumerable<Type> requestWrappedType, IEnumerable<Type> requestBodyTypes = null)
        {
          return new ServiceRemotingRequestJsonMessageBodySerializer();
        }
    
        public IServiceRemotingResponseMessageBodySerializer CreateResponseMessageSerializer(Type serviceInterfaceType, IEnumerable<Type> responseWrappedType, IEnumerable<Type> responseBodyTypes = null)
        {
          return new ServiceRemotingResponseJsonMessageBodySerializer();
        }
    }
    
        class JsonMessageFactory : IServiceRemotingMessageBodyFactory
            {
    
              public IServiceRemotingRequestMessageBody CreateRequest(string interfaceName, string methodName, int numberOfParameters, object wrappedRequestObject)
              {
                return new JsonBody(wrappedRequestObject);
              }
    
              public IServiceRemotingResponseMessageBody CreateResponse(string interfaceName, string methodName, object wrappedRequestObject)
              {
                return new JsonBody(wrappedRequestObject);
              }
            }
    
      class ServiceRemotingRequestJsonMessageBodySerializer : IServiceRemotingRequestMessageBodySerializer
        {
            private JsonSerializer serializer;
    
            public ServiceRemotingRequestJsonMessageBodySerializer()
            {
              serializer = JsonSerializer.Create(new JsonSerializerSettings()
              {
                TypeNameHandling = TypeNameHandling.All
                });
              }
    
              public IOutgoingMessageBody Serialize(IServiceRemotingRequestMessageBody serviceRemotingRequestMessageBody)
             {
               if (serviceRemotingRequestMessageBody == null)
               {
                 return null;
               }          
               using (var writeStream = new MemoryStream())
               {
                 using (var jsonWriter = new JsonTextWriter(new StreamWriter(writeStream)))
                 {
                   serializer.Serialize(jsonWriter, serviceRemotingRequestMessageBody);
                   jsonWriter.Flush();
                   var bytes = writeStream.ToArray();
                   var segment = new ArraySegment<byte>(bytes);
                   var segments = new List<ArraySegment<byte>> { segment };
                   return new OutgoingMessageBody(segments);
                 }
               }
              }
    
              public IServiceRemotingRequestMessageBody Deserialize(IIncomingMessageBody messageBody)
             {
               using (var sr = new StreamReader(messageBody.GetReceivedBuffer()))
               {
                 using (JsonReader reader = new JsonTextReader(sr))
                 {
                   var ob = serializer.Deserialize<JsonBody>(reader);
                   return ob;
                 }
               }
             }
            }
    
      class ServiceRemotingResponseJsonMessageBodySerializer : IServiceRemotingResponseMessageBodySerializer
       {
         private JsonSerializer serializer;
    
        public ServiceRemotingResponseJsonMessageBodySerializer()
        {
          serializer = JsonSerializer.Create(new JsonSerializerSettings()
          {
              TypeNameHandling = TypeNameHandling.All
            });
          }
    
          public IOutgoingMessageBody Serialize(IServiceRemotingResponseMessageBody responseMessageBody)
          {
            if (responseMessageBody == null)
            {
              return null;
            }
    
            using (var writeStream = new MemoryStream())
            {
              using (var jsonWriter = new JsonTextWriter(new StreamWriter(writeStream)))
              {
                serializer.Serialize(jsonWriter, responseMessageBody);
                jsonWriter.Flush();
                var bytes = writeStream.ToArray();
                var segment = new ArraySegment<byte>(bytes);
                var segments = new List<ArraySegment<byte>> { segment };
                return new OutgoingMessageBody(segments);
              }
            }
          }
    
          public IServiceRemotingResponseMessageBody Deserialize(IIncomingMessageBody messageBody)
          {
    
             using (var sr = new StreamReader(messageBody.GetReceivedBuffer()))
             {
               using (var reader = new JsonTextReader(sr))
               {
                 var obj = serializer.Deserialize<JsonBody>(reader);
                 return obj;
               }
             }
           }
       }
    
    class JsonBody : WrappedMessage, IServiceRemotingRequestMessageBody, IServiceRemotingResponseMessageBody
    {
          public JsonBody(object wrapped)
          {
            this.Value = wrapped;
          }
    
          public void SetParameter(int position, string parameName, object parameter)
          {  //Not Needed if you are using WrappedMessage
            throw new NotImplementedException();
          }
    
          public object GetParameter(int position, string parameName, Type paramType)
          {
            //Not Needed if you are using WrappedMessage
            throw new NotImplementedException();
          }
    
          public void Set(object response)
          { //Not Needed if you are using WrappedMessage
            throw new NotImplementedException();
          }
    
          public object Get(Type paramType)
          {  //Not Needed if you are using WrappedMessage
            throw new NotImplementedException();
          }
    }
    
  2. 使用远程处理侦听器的 JsonSerializationProvider 重写默认的序列化提供程序。Override the default serialization provider with JsonSerializationProvider for a remoting listener.

    protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
    {
       return new[]
       {
           new ServiceInstanceListener((c) =>
           {
               return new FabricTransportServiceRemotingListener(c, this,
                   new ServiceRemotingJsonSerializationProvider());
           })
       };
    }
    
  3. 使用远程处理客户端工厂的 JsonSerializationProvider 重写默认的序列化提供程序。Override the default serialization provider with JsonSerializationProvider for a remoting client factory.

    var proxyFactory = new ServiceProxyFactory((c) =>
    {
        return new FabricTransportServiceRemotingClientFactory(
        serializationProvider: new ServiceRemotingJsonSerializationProvider());
      });
    

后续步骤Next steps