Reliable Services ile C# dilinde hizmet uzaktan iletişim

Web API'si, Windows Communication Foundation veya diğerleri gibi belirli bir iletişim protokolüne veya yığınına bağlı olmayan hizmetler için Reliable Services çerçevesi, hizmetler için uzaktan yordam çağrılarını hızlı ve kolay bir şekilde ayarlamak için uzaktan iletişim mekanizması sağlar. Bu makalede, C# ile yazılmış hizmetler için uzaktan yordam çağrılarının nasıl ayarlanacağı açıklanır.

Hizmette uzaktan iletişim ayarlama

Bir hizmet için uzaktan iletişimi iki basit adımda ayarlayabilirsiniz:

  1. Hizmetinizin uygulayacağı bir arabirim oluşturun. Bu arabirim, hizmetinizdeki bir uzak yordam çağrısı için kullanılabilen yöntemleri tanımlar. Yöntemler, görev döndüren zaman uyumsuz yöntemler olmalıdır. Arabirimin hizmetin uzaktan iletişim arabirimine sahip olduğunu belirtmek için uygulaması Microsoft.ServiceFabric.Services.Remoting.IService gerekir.
  2. Hizmetinizde uzaktan iletişim dinleyicisi kullanın. Uzaktan iletişim dinleyicisi, uzaktan iletişim özellikleri sağlayan bir ICommunicationListener uygulamadır. Ad alanı, Microsoft.ServiceFabric.Services.Remoting.Runtime varsayılan uzaktan iletişim aktarım protokolü kullanılarak uzaktan iletişim dinleyicisi oluşturmak için kullanılabilecek durum bilgisi olmayan ve durum bilgisi olan hizmetler için uzantı yöntemini CreateServiceRemotingInstanceListeners içerir.

Not

Ad Remoting alanı adlı Microsoft.ServiceFabric.Services.Remotingayrı bir NuGet paketi olarak kullanılabilir.

Örneğin, aşağıdaki durum bilgisi olmayan hizmet, bir uzak yordam çağrısı üzerinden "Merhaba Dünya" almak için tek bir yöntemi kullanıma sunar.

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

Not

Hizmet arabirimindeki bağımsız değişkenler ve dönüş türleri basit, karmaşık veya özel türler olabilir, ancak .NET DataContractSerializer tarafından seri hale getirilebilmeleri gerekir.

Uzak hizmet yöntemlerini çağırma

Not

Birden fazla bölüm kullanıyorsanız, ServiceProxy.Create() için uygun ServicePartitionKey sağlanmalıdır. Bu, tek bir bölüm senaryosu için gerekli değildir.

Uzaktan iletişim yığını kullanılarak bir hizmette çağrı yöntemleri, sınıfı aracılığıyla Microsoft.ServiceFabric.Services.Remoting.Client.ServiceProxy hizmete yerel bir ara sunucu kullanılarak yapılır. yöntemi, ServiceProxy hizmetin uyguladığı arabirimi kullanarak yerel bir ara sunucu oluşturur. Bu ara sunucuyla, arabirimdeki yöntemleri uzaktan çağırabilirsiniz.


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

string message = await helloWorldClient.HelloWorldAsync();

Uzaktan iletişim çerçevesi, hizmet tarafından istemciye atılan özel durumları yayılır. Sonuç olarak, ServiceProxykullanıldığında istemci hizmet tarafından oluşan özel durumları işlemekle sorumludur.

Hizmet proxy'si ömrü

Hizmet proxy'si oluşturma basit bir işlemdir, bu nedenle istediğiniz kadar oluşturabilirsiniz. Hizmet proxy'si örnekleri, ihtiyaç duyulduğu sürece yeniden kullanılabilir. Bir uzak yordam çağrısı özel durum oluşturursa, yine de aynı proxy örneğini yeniden kullanabilirsiniz. Her hizmet proxy'si, ileti göndermek için kullanılan bir iletişim istemcisi içerir. Uzak çağrılar çağrılırken, iletişim istemcisinin geçerli olup olmadığını belirlemek için iç denetimler gerçekleştirilir. Bu denetimlerin sonuçlarına bağlı olarak, iletişim istemcisi gerekirse yeniden oluşturulur. Bu nedenle, bir özel durum oluşursa yeniden oluşturmanız ServiceProxygerekmez.

Hizmet proxy'si fabrika ömrü

ServiceProxyFactory , farklı uzaktan iletişim arabirimleri için ara sunucu örnekleri oluşturan bir fabrikadır. Ara sunucu oluşturmak için API'yi ServiceProxyFactory.CreateServiceProxy kullanırsanız, çerçeve tek bir hizmet ara sunucusu oluşturur. IServiceRemotingClientFactory özelliklerini geçersiz kılmanız gerektiğinde el ile bir tane oluşturmak yararlıdır. Fabrika oluşturma pahalı bir işlemdir. Hizmet ara sunucusu fabrikası, iletişim istemcisinin iç önbelleğini tutar. En iyi yöntem, hizmet ara sunucusu fabrikasını mümkün olduğunca uzun süre önbelleğe almaktır.

Uzaktan iletişim özel durum işleme

Hizmet API'sinin oluşturduğu tüm uzak özel durumlar, istemciye AggregateException olarak geri gönderilir. Uzak özel durumlar DataContract tarafından seri hale getirilebilir. Değilse, ara sunucu API'si ServiceException'ı içinde serileştirme hatasıyla oluşturur.

Hizmet proxy'si, oluşturulduğu hizmet bölümü için tüm yük devretme özel durumlarını işler. Yük devretme özel durumları (geçici olmayan özel durumlar) varsa uç noktaları yeniden çözümler ve çağrıyı doğru uç noktayla yeniden dener. Yük devretme özel durumları için yeniden deneme sayısı belirsizdir. Geçici özel durumlar oluşursa, ara sunucu çağrıyı yeniden denenir.

Varsayılan yeniden deneme parametreleri OperationRetrySettings tarafından sağlanır.

Kullanıcı, OperationRetrySettings nesnesini ServiceProxyFactory oluşturucusna geçirerek bu değerleri yapılandırabilir.

Uzaktan iletişim V2 yığınını kullanma

NuGet uzaktan iletişim paketinin 2.8 sürümünden itibaren uzaktan iletişim V2 yığınını kullanma seçeneğiniz vardır. Uzaktan iletişim V2 yığını daha iyi performans gösterir. Ayrıca özel serileştirme ve daha takılabilir API'ler gibi özellikler de sağlar. Şablon kodu uzaktan iletişim V1 yığınını kullanmaya devam eder. Uzaktan iletişim V2, V1 (önceki uzaktan iletişim yığını) ile uyumlu değildir. Hizmet kullanılabilirliği üzerindeki etkileri önlemek için V1'den V2'ye yükseltme makalesindeki yönergeleri izleyin.

V2 yığınını etkinleştirmek için aşağıdaki yaklaşımlar kullanılabilir.

V2 yığınını kullanmak için derleme özniteliği kullanma

Bu adımlar, bir derleme özniteliği kullanarak şablon kodunu V2 yığınını kullanacak şekilde değiştirir.

  1. Hizmet bildiriminde uç nokta kaynağını "ServiceEndpoint" "ServiceEndpointV2" olarak değiştirin.

    <Resources>
     <Endpoints>
       <Endpoint Name="ServiceEndpointV2" />
     </Endpoints>
    </Resources>
    
  2. Microsoft.ServiceFabric.Services.Remoting.Runtime.CreateServiceRemotingInstanceListeners Uzaktan iletişim dinleyicileri oluşturmak için uzantı yöntemini kullanın (hem V1 hem de V2 için eşittir).

     protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
     {
         return this.CreateServiceRemotingInstanceListeners();
     }
    
  3. Uzaktan iletişim arabirimlerini içeren derlemeyi bir FabricTransportServiceRemotingProvider öznitelikle işaretleyin.

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

İstemci projesinde kod değişikliği gerekmez. Daha önce gösterilen derleme özniteliğinin kullanıldığından emin olmak için arabirim derlemesi ile istemci derlemesini oluşturun.

V2 yığınını kullanmak için açık V2 sınıflarını kullanma

Derleme özniteliği kullanmaya alternatif olarak, V2 yığını açık V2 sınıfları kullanılarak da etkinleştirilebilir.

Bu adımlar, şablon kodunu açık V2 sınıflarını kullanarak V2 yığınını kullanacak şekilde değiştirir.

  1. Hizmet bildiriminde uç nokta kaynağını "ServiceEndpoint" "ServiceEndpointV2" olarak değiştirin.

    <Resources>
     <Endpoints>
       <Endpoint Name="ServiceEndpointV2" />
     </Endpoints>
    </Resources>
    
  2. Ad alanından FabricTransportServiceRemotingListener kullanın Microsoft.ServiceFabric.Services.Remoting.V2.FabricTransport.Runtime .

    protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
     {
         return new[]
         {
             new ServiceInstanceListener((c) =>
             {
                 return new FabricTransportServiceRemotingListener(c, this);
    
             })
         };
     }
    
  3. İstemci oluşturmak için ad alanından FabricTransportServiceRemotingClientFactory Microsoft.ServiceFabric.Services.Remoting.V2.FabricTransport.Client kullanın.

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

Uzaktan iletişim V1'den uzaktan iletişim V2'ye yükseltme

V1'den V2'ye yükseltmek için iki aşamalı yükseltmeler gerekir. Bu dizideki adımları izleyin.

  1. Bu özniteliği kullanarak V1 hizmetini V2 hizmetine yükseltin. Bu değişiklik, hizmetin V1 ve V2 dinleyicisinde dinlemesini sağlar.

    a. Hizmet bildirimine "ServiceEndpointV2" adlı bir uç nokta kaynağı ekleyin.

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

    b. Uzaktan iletişim dinleyicisi oluşturmak için aşağıdaki uzantı yöntemini kullanın.

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

    c. V1 ve V2 dinleyicisini ve V2 istemcisini kullanmak için uzaktan iletişim arabirimlerine bir derleme özniteliği ekleyin.

    [assembly: FabricTransportServiceRemotingProvider(RemotingListenerVersion = RemotingListenerVersion.V2|RemotingListenerVersion.V1, RemotingClientVersion = RemotingClientVersion.V2)]
    
    
  2. V2 istemci özniteliğini kullanarak V1 istemcisini bir V2 istemcisine yükseltin. Bu adım, istemcinin V2 yığınını kullanmasını sağlar. İstemci projesinde/hizmetinde değişiklik yapılması gerekmez. Güncelleştirilmiş arabirim derlemesi ile istemci projeleri oluşturmak yeterlidir.

  3. Bu adım isteğe bağlıdır. V2 dinleyici özniteliğini kullanın ve ardından V2 hizmetini yükseltin. Bu adım, hizmetin yalnızca V2 dinleyicisinde dinlemesini sağlar.

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

Uzaktan iletişim V2 (arabirim uyumlu) yığınını kullanma

Uzaktan iletişim V2 (arabirim uyumlu) yığını V2_1 olarak bilinir ve en güncel sürümdür. V2 uzaktan iletişim yığınının tüm özelliklerine sahiptir. Arabirim yığını uzaktan iletişim V1 yığınıyla uyumludur, ancak V2 ve V1 ile geriye dönük olarak uyumlu değildir. Hizmet kullanılabilirliğini etkilemeden V1'den V2_1 yükseltmek için V1'den V2'ye yükseltme (arabirim uyumlu) makalesindeki adımları izleyin.

Uzaktan iletişim V2 (arabirim uyumlu) yığınını kullanmak için derleme özniteliği kullanma

V2_1 yığınına geçmek için bu adımları izleyin.

  1. Hizmet bildirimine "ServiceEndpointV2_1" adlı bir uç nokta kaynağı ekleyin.

    <Resources>
     <Endpoints>
       <Endpoint Name="ServiceEndpointV2_1" />  
     </Endpoints>
    </Resources>
    
  2. Uzaktan iletişim dinleyicisi oluşturmak için uzaktan iletişim uzantısı yöntemini kullanın.

     protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
     {
         return this.CreateServiceRemotingInstanceListeners();
     }
    
  3. Uzaktan iletişim arabirimlerine bir derleme özniteliği ekleyin.

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

İstemci projesinde değişiklik gerekmez. Önceki derleme özniteliğinin kullanıldığından emin olmak için arabirim derlemesi ile istemci derlemesini oluşturun.

V2 (arabirim uyumlu) sürümü için bir dinleyici/istemci fabrikası oluşturmak için açık uzaktan iletişim sınıflarını kullanma

Şu adımları izleyin:

  1. Hizmet bildirimine "ServiceEndpointV2_1" adlı bir uç nokta kaynağı ekleyin.

    <Resources>
     <Endpoints>
       <Endpoint Name="ServiceEndpointV2_1" />  
     </Endpoints>
    </Resources>
    
  2. Uzaktan iletişim V2 dinleyicisini kullanın. Kullanılan varsayılan hizmet uç noktası kaynak adı "ServiceEndpointV2_1." Hizmet bildiriminde tanımlanmalıdır.

    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 istemci fabrikasını kullanın.

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

Uzaktan iletişim V1'den uzaktan iletişim V2'ye yükseltme (arabirim uyumlu)

V1'den V2'ye (arabirim uyumlu, V2_1 olarak bilinir) yükseltmek için iki aşamalı yükseltmeler gerekir. Bu dizideki adımları izleyin.

Not

V1'den V2'ye yükseltirken, ad alanının Remoting V2 kullanacak şekilde güncelleştirildiğinden emin olun. Örnek: Microsoft.ServiceFabric.Services.Remoting.V2.FabricTransport.Client

  1. Aşağıdaki özniteliği kullanarak V1 hizmetini V2_1 hizmetine yükseltin. Bu değişiklik, hizmetin V1'de ve V2_1 dinleyicisinde dinlemesini sağlar.

    a. Hizmet bildirimine "ServiceEndpointV2_1" adlı bir uç nokta kaynağı ekleyin.

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

    b. Uzaktan iletişim dinleyicisi oluşturmak için aşağıdaki uzantı yöntemini kullanın.

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

    c. V1, V2_1 dinleyici ve V2_1 istemcisini kullanmak için uzaktan iletişim arabirimlerine bir derleme özniteliği ekleyin.

    [assembly: FabricTransportServiceRemotingProvider(RemotingListenerVersion = RemotingListenerVersion.V2_1 | RemotingListenerVersion.V1, RemotingClientVersion = RemotingClientVersion.V2_1)]
    
    
  2. V2_1 istemci özniteliğini kullanarak V1 istemcisini V2_1 istemcisine yükseltin. Bu adım, istemcinin V2_1 yığınını kullandığından emin olur. İstemci projesinde/hizmetinde değişiklik yapılması gerekmez. Güncelleştirilmiş arabirim derlemesi ile istemci projeleri oluşturmak yeterlidir.

  3. Bu adım isteğe bağlıdır. V1 dinleyici sürümünü özniteliğinden kaldırın ve ardından V2 hizmetini yükseltin. Bu adım, hizmetin yalnızca V2 dinleyicisinde dinlemesini sağlar.

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

Sarmalanmış uzaktan iletişim iletisiyle özel serileştirme kullanma

Uzaktan sarmalanmış ileti için, tüm parametreleri içinde bir alan olarak içeren tek bir sarmalanmış nesne oluştururuz. Şu adımları izleyin:

  1. IServiceRemotingMessageSerializationProvider Özel serileştirme için uygulama sağlamak için arabirimini uygulayın. Bu kod parçacığı uygulamanın nasıl göründüğünü gösterir.

    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. Uzaktan iletişim dinleyicisi için varsayılan serileştirme sağlayıcısını ile JsonSerializationProvider geçersiz kılın.

    protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
    {
        return new[]
        {
            new ServiceInstanceListener((c) =>
            {
                return new FabricTransportServiceRemotingListener(context, _calculatorFactory.GetCalculator(Context), serializationProvider: new         ServiceRemotingJsonSerializationProvider());
            })
        };
    }
    
  3. Uzaktan iletişim istemci fabrikası için varsayılan serileştirme sağlayıcısını ile JsonSerializationProvider geçersiz kılın.

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

Sonraki adımlar