Udostępnij za pośrednictwem


Omówienie serializacji wyjątków zdalnego połączenia

Serializacja oparta na binaryFormatter nie jest bezpieczna, więc nie używaj klasy BinaryFormatter do przetwarzania danych. Aby uzyskać więcej informacji dotyczących implikacji zabezpieczeń, zobacz Ryzyka deserializacji przy użyciu BinaryFormattera i powiązanych typów.

Usługa Azure Service Fabric używa narzędzia BinaryFormatter do serializacji wyjątków. Począwszy od wersji 9.0 ServiceFabric, serializacja oparta na kontrakcie danych dla zdalnych wyjątków jest dostępna jako funkcja opcjonalna. Zachęcamy do wyboru serializacji wyjątków zdalnych za pomocą DataContract, wykonując kroki opisane w tym artykule.

Obsługa serializacji wyjątków remoting opartych na programie BinaryFormatter zostanie wycofana w przyszłości.

Włącz serializację kontraktu danych dla wyjątków zdalnych

Uwaga

Serializacja kontraktu danych dla wyjątków zdalnej komunikacji jest dostępna tylko w przypadku usług zdalnej komunikacji V2/V2_1.

Aby włączyć serializację danych kontraktowych dla wyjątków zdalnych wywołań:

  1. Włącz serializację wyjątków komunikacji zdalnej DataContract po stronie usługi przy użyciu FabricTransportRemotingListenerSettings.ExceptionSerializationTechnique podczas tworzenia odbiornika komunikacji zdalnej.

    • StatelessService

      protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
      {
          return new[]
          {
              new ServiceInstanceListener(serviceContext =>
                  new FabricTransportServiceRemotingListener(
                      serviceContext,
                      this,
                      new FabricTransportRemotingListenerSettings
                      {
                          ExceptionSerializationTechnique = FabricTransportRemotingListenerSettings.ExceptionSerialization.Default,
                      }),
                   "ServiceEndpointV2")
          };
      }
      
    • StatefulService

      protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners()
      {
          return new[]
          {
              new ServiceReplicaListener(serviceContext =>
                  new FabricTransportServiceRemotingListener(
                      serviceContext,
                      this,
                      new FabricTransportRemotingListenerSettings
                      {
                          ExceptionSerializationTechnique = FabricTransportRemotingListenerSettings.ExceptionSerialization.Default,
                      }),
                  "ServiceEndpointV2")
          };
      }
      
    • AktorService
      Aby włączyć serializację wyjątków zdalnego wywołania w DataContract na usłudze aktora, nadpisz metodę CreateServiceReplicaListeners() poprzez rozszerzenie ActorService.

      protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners()
      {
          return new List<ServiceReplicaListener>
          {
              new ServiceReplicaListener(_ =>
              {
                  return new FabricTransportActorServiceRemotingListener(
                      this,
                      new FabricTransportRemotingListenerSettings
                      {
                          ExceptionSerializationTechnique = FabricTransportRemotingListenerSettings.ExceptionSerialization.Default,
                      });
              },
              "MyActorServiceEndpointV2")
          };
      }
      

    Jeśli oryginalny wyjątek ma wiele poziomów wyjątków wewnętrznych, można kontrolować liczbę poziomów wyjątków wewnętrznych, które mają być serializowane, ustawiając wartość FabricTransportRemotingListenerSettings.RemotingExceptionDepth.

  2. Włącz serializację wyjątków przekazywania zdalnego DataContract na kliencie przy użyciu FabricTransportRemotingSettings.ExceptionDeserializationTechnique podczas tworzenia fabryki klienta.

    • Tworzenie ServiceProxyFactory

      var serviceProxyFactory = new ServiceProxyFactory(
      (callbackClient) =>
      {
          return new FabricTransportServiceRemotingClientFactory(
              new FabricTransportRemotingSettings
              {
                  ExceptionDeserializationTechnique = FabricTransportRemotingSettings.ExceptionDeserialization.Default,
              },
              callbackClient);
      });
      
    • AktorProxyFactory

      var actorProxyFactory = new ActorProxyFactory(
      (callbackClient) =>
      {
          return new FabricTransportActorRemotingClientFactory(
              new FabricTransportRemotingSettings
              {
                  ExceptionDeserializationTechnique = FabricTransportRemotingSettings.ExceptionDeserialization.Default,
              },
              callbackClient);
      });
      
  3. Serializacja wyjątków zdalnej komunikacji DataContract konwertuje wyjątek na obiekt transferu danych (DTO) po stronie usługi. Obiekt DTO jest konwertowany z powrotem na wyjątek po stronie klienta. Użytkownicy muszą zarejestrować się ExceptionConvertor , aby przekonwertować żądane wyjątki na obiekty DTO i na odwrót.

    Struktura implementuje konwertery dla następującej listy wyjątków. Jeśli kod usługi użytkownika zależy od wyjątków spoza poniższej listy na potrzeby implementacji ponawiania i obsługi wyjątków, użytkownicy muszą implementować i rejestrować konwertery dla takich wyjątków.

    • Wszystkie wyjątki usługi Service Fabric pochodzące z System.Fabric.FabricException
    • Wyjątek SystemExceptions pochodzący z System.SystemException
      • System.AccessViolationException (Wyjątek naruszenia dostępu)
      • System.AppDomainUnloadedException
      • System.ArgumentException
      • System.ArithmeticException
      • System.ArrayTypeMismatchException
      • System.BadImageFormatException
      • System.CannotUnloadAppDomainException
      • System.Collections.Generic.KeyNotFoundException
      • System.ContextMarshalException
      • System.DataMisalignedException
      • System.ExecutionEngineException
      • System.FormatException
      • System.IndexOutOfRangeException
      • System.InsufficientExecutionStackException
      • System.InvalidCastException
      • System.InvalidOperationException
      • System.InvalidProgramException
      • System.IO.InternalBufferOverflowException
      • System.IO.InvalidDataException
      • System.IO.IOException
      • System.MemberAccessException
      • System.MulticastNotSupportedException
      • System.NotImplementedException
      • System.NotSupportedException (Nieobsługiwany wyjątek)
      • System.NullReferenceException
      • System.OperationCanceledException
      • System.OutOfMemoryException
      • System.RankException
      • System.Reflection.AmbiguousMatchException
      • System.Reflection.ReflectionTypeLoadException
      • System.Resources.MissingManifestResourceException
      • System.Resources.MissingSatelliteAssemblyException
      • System.Runtime.InteropServices.ExternalException
      • System.Runtime.InteropServices.InvalidComObjectException
      • System.Runtime.InteropServices.InvalidOleVariantTypeException
      • System.Runtime.InteropServices.MarshalDirectiveException
      • System.Runtime.InteropServices.SafeArrayRankMismatchException
      • System.Runtime.InteropServices.SafeArrayTypeMismatchException
      • System.Runtime.Serialization.SerializationException
      • System.StackOverflowException
      • System.Threading.AbandonedMutexException
      • System.Threading.SemaphoreFullException
      • System.Threading.SynchronizationLockException
      • System.Threading.ThreadInterruptedException
      • System.Threading.ThreadStateException
      • System.TimeoutException
      • System.TypeInitializationException
      • System.TypeLoadException
      • System.TypeUnloadedException
      • System.UnauthorizedAccessException
      • System.ArgumentNullException
      • System.IO.FileNotFoundException
      • System.IO.DirectoryNotFoundException
      • System.ObjectDisposedException
      • System.AggregateException

Przykładowa implementacja konwertora po stronie usługi dla wyjątku niestandardowego

Poniższy przykład to implementacja referencyjna IExceptionConvertor po stronie usługi i klienta dla dobrze znanego typu wyjątku . CustomException

  • CustomException

    class CustomException : Exception
    {
        public CustomException(string message, string field1, string field2)
            : base(message)
        {
            this.Field1 = field1;
            this.Field2 = field2;
        }
    
        public CustomException(string message, Exception innerEx, string field1, string field2)
            : base(message, innerEx)
        {
            this.Field1 = field1;
            this.Field2 = field2;
        }
    
        public string Field1 { get; set; }
    
        public string Field2 { get; set; }
    }
    
  • IExceptionConvertor implementacja po stronie usługi :

    class CustomConvertorService : Microsoft.ServiceFabric.Services.Remoting.V2.Runtime.IExceptionConvertor
    {
        public Exception[] GetInnerExceptions(Exception originalException)
        {
            return originalException.InnerException == null ? null : new Exception[] { originalException.InnerException };
        }
    
        public bool TryConvertToServiceException(Exception originalException, out ServiceException serviceException)
        {
            serviceException = null;
            if (originalException is CustomException customEx)
            {
                serviceException = new ServiceException(customEx.GetType().FullName, customEx.Message);
                serviceException.ActualExceptionStackTrace = originalException.StackTrace;
                serviceException.ActualExceptionData = new Dictionary<string, string>()
                    {
                        { "Field1", customEx.Field1 },
                        { "Field2", customEx.Field2 },
                    };
    
                return true;
            }
    
            return false;
        }
    }
    

Rzeczywisty wyjątek zaobserwowany podczas wykonywania zdalnego połączenia jest przekazywany jako dane wejściowe do TryConvertToServiceException. Jeśli typ wyjątku jest dobrze znany, TryConvertToServiceException należy przekonwertować oryginalny wyjątek na ServiceException i zwrócić go jako parametr wyjściowy. Wartość true powinna zostać zwrócona, jeśli oryginalny typ wyjątku jest dobrze znany, a oryginalny wyjątek został pomyślnie przekonwertowany na ServiceException. W przeciwnym razie wartość to fałsz.

Lista wyjątków wewnętrznych na bieżącym poziomie ma być zwracana przez GetInnerExceptions().

  • IExceptionConvertor implementacja po stronie klienta :

    class CustomConvertorClient : Microsoft.ServiceFabric.Services.Remoting.V2.Client.IExceptionConvertor
    {
        public bool TryConvertFromServiceException(ServiceException serviceException, out Exception actualException)
        {
            return this.TryConvertFromServiceException(serviceException, (Exception)null, out actualException);
        }
    
        public bool TryConvertFromServiceException(ServiceException serviceException, Exception innerException, out Exception actualException)
        {
            actualException = null;
            if (serviceException.ActualExceptionType == typeof(CustomException).FullName)
            {
                actualException = new CustomException(
                    serviceException.Message,
                    innerException,
                    serviceException.ActualExceptionData["Field1"],
                    serviceException.ActualExceptionData["Field2"]);
    
                return true;
            }
    
            return false;
        }
    
        public bool TryConvertFromServiceException(ServiceException serviceException, Exception[] innerExceptions, out Exception actualException)
        {
            throw new NotImplementedException();
        }
    }
    

ServiceException jest przekazywane jako parametr do TryConvertFromServiceException wraz z przekonwertowanym elementem innerException[s]. Jeśli rzeczywisty typ wyjątku, ServiceException.ActualExceptionType, jest znany, konwertujący powinien utworzyć rzeczywisty obiekt wyjątku z ServiceException i innerException[s].

  • IExceptionConvertor rejestracja po stronie usługi :

    Aby zarejestrować konwertery, CreateServiceInstanceListeners musi być nadpisane, a lista klas IExceptionConvertor należy przekazać podczas tworzenia wystąpienia RemotingListener.

    • StatelessService

      protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
      {
          return new[]
          {
              new ServiceInstanceListener(serviceContext =>
                  new FabricTransportServiceRemotingListener(
                      serviceContext,
                      this,
                      new FabricTransportRemotingListenerSettings
                      {
                          ExceptionSerializationTechnique = FabricTransportRemotingListenerSettings.ExceptionSerialization.Default,
                      },
                      exceptionConvertors: new[]
                      {
                          new CustomConvertorService(),
                      }),
                   "ServiceEndpointV2")
          };
      }
      
    • StatefulService

      protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners()
      {
          return new[]
          {
              new ServiceReplicaListener(serviceContext =>
                  new FabricTransportServiceRemotingListener(
                      serviceContext,
                      this,
                      new FabricTransportRemotingListenerSettings
                      {
                          ExceptionSerializationTechnique = FabricTransportRemotingListenerSettings.ExceptionSerialization.Default,
                      },
                      exceptionConvertors: new []
                      {
                          new CustomConvertorService(),
                      }),
                  "ServiceEndpointV2")
          };
      }
      
    • AktorService

      protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners()
      {
          return new List<ServiceReplicaListener>
          {
              new ServiceReplicaListener(_ =>
              {
                  return new FabricTransportActorServiceRemotingListener(
                      this,
                      new FabricTransportRemotingListenerSettings
                      {
                          ExceptionSerializationTechnique = FabricTransportRemotingListenerSettings.ExceptionSerialization.Default,
                      },
                      exceptionConvertors: new[]
                      {
                          new CustomConvertorService(),
                      });
              },
              "MyActorServiceEndpointV2")
          };
      }
      
  • IExceptionConvertor rejestracja po stronie klienta :

    Aby zarejestrować IExceptionConvertor konwertery, lista klas musi zostać przekazana podczas tworzenia wystąpienia ClientFactory.

    • Tworzenie ServiceProxyFactory

      var serviceProxyFactory = new ServiceProxyFactory(
      (callbackClient) =>
      {
         return new FabricTransportServiceRemotingClientFactory(
             new FabricTransportRemotingSettings
             {
                 ExceptionDeserializationTechnique = FabricTransportRemotingSettings.ExceptionDeserialization.Default,
             },
             callbackClient,
             exceptionConvertors: new[]
             {
                 new CustomConvertorClient(),
             });
      });
      
    • Tworzenie aktoraProxyFactory

      var actorProxyFactory = new ActorProxyFactory(
      (callbackClient) =>
      {
          return new FabricTransportActorRemotingClientFactory(
              new FabricTransportRemotingSettings
              {
                  ExceptionDeserializationTechnique = FabricTransportRemotingSettings.ExceptionDeserialization.Default,
              },
              callbackClient,
              exceptionConvertors: new[]
              {
                  new CustomConvertorClient(),
              });
      });
      

Uwaga

Jeśli framework znajdzie konwerter dla wyjątku, przekonwertowany (rzeczywisty) wyjątek jest opakowany wewnątrz AggregateException i jest zgłaszany do zdalnego interfejsu API (proxy). Jeśli framework nie może odnaleźć konwertora, to ServiceException, który zawiera wszystkie szczegóły rzeczywistego wyjątku, jest opakowany wewnątrz AggregateException i zostaje zgłoszony.

Uaktualnij istniejącą usługę, aby umożliwić serializację kontraktów danych do wyjątków zdalnych.

Aby zaktualizować, istniejące usługi muszą postępować według następującej kolejności (Najpierw usługa). Niepowodzenie wykonania tej kolejności może spowodować niewłaściwe zachowanie logiki ponawiania prób i obsługi wyjątków.

  1. Zaimplementuj klasy po stronie usługi dla żądanych wyjątków, jeśli są potrzebne. Zaktualizuj logikę rejestracji odbiornika zdalnego za pomocą ExceptionSerializationTechnique i listy IExceptionConvertorklas. Uaktualnij istniejącą usługę, aby zastosować zmiany serializacji wyjątków.

  2. Zaimplementuj klasy po stronie ExceptionConvertorklienta dla żądanych wyjątków, jeśli istnieją. Zaktualizuj logikę tworzenia ProxyFactory z ExceptionSerializationTechnique i listą klas IExceptionConvertor. Uaktualnij istniejącego klienta, aby zastosować zmiany serializacji wyjątków.

Następne kroki