Partager via


Vue d’ensemble de la sérialisation des exceptions de communication à distance

La sérialisation basée sur BinaryFormatter n’est pas sécurisée. N’utilisez donc pas BinaryFormatter pour le traitement des données. Pour plus d’informations sur les implications de sécurité, consultez Les risques de désérialisation dans l’utilisation de BinaryFormatter et de types associés.

Service Fabric utilisait BinaryFormatter pour sérialiser des exceptions. À partir de ServiceFabric v9.0, la sérialisation basée sur le contrat de données pour les exceptions de communication à distance est mise à disposition en tant que fonctionnalité facultative. Nous vous recommandons d’opter pour la sérialisation de l’exception de communication à distance DataContract en suivant les étapes décrites dans cet article.

La prise en charge de la sérialisation de l’exception de la communication à distance basée sur BinaryFormatter sera dépréciée à l’avenir.

Activation de la sérialisation du contrat de données pour les exceptions de la communication à distance

Notes

La sérialisation du contrat de données pour les exceptions de la communication à distance n’est disponible que pour les services de communication à distance V2/V2_1.

Pour activer la sérialisation du contrat de données pour les exceptions de la communication à distance

  1. Activez la sérialisation de l’exception de communication à distance DataContract côté Service à l’aide de FabricTransportRemotingListenerSettings.ExceptionSerializationTechnique lors de la création de l’écouteur de communication à distance.

    • 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")
          };
      }
      
    • ActorService
      Pour activer la sérialisation de l’exception de communication à distance DataContract sur le service des acteurs, remplacez CreateServiceReplicaListeners() en étendant ActorService

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

    Si l’exception d’origine comporte plusieurs niveaux d’exceptions internes, vous pouvez contrôler le nombre de niveaux d’exceptions internes à sérialiser en définissant FabricTransportRemotingListenerSettings.RemotingExceptionDepth.

  2. Activer la sérialisation de l’exception de communication à distance DataContract sur le Client en utilisant FabricTransportRemotingSettings.ExceptionDeserializationTechnique lors de la création de la fabrique cliente

    • Création de ServiceProxyFactory

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

      var actorProxyFactory = new ActorProxyFactory(
      (callbackClient) =>
      {
          return new FabricTransportActorRemotingClientFactory(
              new FabricTransportRemotingSettings
              {
                  ExceptionDeserializationTechnique = FabricTransportRemotingSettings.ExceptionDeserialization.Default,
              },
              callbackClient);
      });
      
  3. La sérialisation de l’exception de communication à distance DataContract convertit une exception en objet de transfert de données (DTO) côté service. Le DTO est converti en exception côté client. Les utilisateurs doivent inscrire ExceptionConvertor pour convertir les exceptions souhaitées en objets DTO et vice versa.

    L’infrastructure implémente les converteurs pour la liste suivante d’exceptions. Si le code du service utilisateur dépend d’exceptions qui ne figurent pas dans la liste ci-dessous pour l’implémentation de nouvelles tentatives, la gestion des exceptions, etc., l’utilisateur doit implémenter et inscrire des outils de conversion pour ces exceptions.

    • Toutes les exceptions Service Fabric dérivées de System.Fabric.FabricException
    • SystemExceptions dérivées de System.SystemException
      • System.AccessViolationException
      • 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
      • 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

Exemple d’implémentation de l’outil de conversion côté service pour une exception personnalisée

Vous trouverez ci-dessous une implémentation IExceptionConvertor de référence côté Service et Client pour un type d’exception bien connu 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; }
    }
    
  • IExceptionConvertorImplémentation du côté Service :

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

L’exception réelle observée lors de l’exécution de l’appel de communication à distance est passée en tant qu’entrée TryConvertToServiceException. Si le type de l’exception est bien connu, TryConvertToServiceException doit convertir l’exception d’origine en ServiceException et la retourner en tant que paramètre de sortie. Une valeur vraie doit être renvoyée si le type d'exception d'origine est bien connu et si l'exception d'origine est convertie avec succès en ServiceException. Sinon, la valeur est false.

Une liste d’exceptions internes au niveau actuel doit être retournée par GetInnerExceptions().

  • IExceptionConvertorImplémentation du côté Client :

    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 est passé en tant que paramètre à TryConvertFromServiceException ainsi que l’élément innerException[s] converti. Si le type d’exception réel ,ServiceException.ActualExceptionType, est connu, l’outil de conversion doit créer un objet d’exception réel à partir de ServiceException et de innerException[s].

  • IExceptionConvertor Inscription côté Service :

    Pour inscrire des converteurs, CreateServiceInstanceListeners vous devez être remplacés et la liste des classes doit être passée pendant la création de IExceptionConvertor l’instance 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")
          };
      }
      
    • ActorService

      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 Inscription côté Client :

    Pour inscrire des converteurs, la liste des IExceptionConvertor classes doit être passée pendant que vous créez l’instance ClientFactory .

    • Création de ServiceProxyFactory

      var serviceProxyFactory = new ServiceProxyFactory(
      (callbackClient) =>
      {
         return new FabricTransportServiceRemotingClientFactory(
             new FabricTransportRemotingSettings
             {
                 ExceptionDeserializationTechnique = FabricTransportRemotingSettings.ExceptionDeserialization.Default,
             },
             callbackClient,
             exceptionConvertors: new[]
             {
                 new CustomConvertorClient(),
             });
      });
      
    • Création de ActorProxyFactory

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

Notes

Si le framework trouve le convertisseur pour l'exception, l'exception convertie (réelle) est enveloppée dans AggregateException et est lancée à l'API de remoting (proxy). Si le framework ne parvient pas à trouver l’outil de conversion, ServiceException qui contient tous les détails de l’exception réelle est encapsulé dans AggregateException et levé.

Mettre à niveau un service existant pour activer la sérialisation des contrats de données pour les exceptions de communication à distance

Les services existants doivent suivre l’ordre ci-dessous (en commençant par Service) pour la mise à niveau. Le non-respect de cet ordre peut entraîner un mauvais comportement dans la logique de relance et le traitement des exceptions.

  1. Implémentez les ExceptionConvertor côté Service pour les exceptions souhaitées, le cas échéant. Mettez à jour la logique d’inscription de l’écouteur de communication à distance avec ExceptionSerializationTechnique et la liste des classes IExceptionConvertor. Mettre à niveau le service existant pour appliquer les modifications de sérialisation des exceptions.

  2. Implémentez les ExceptionConvertor côté Client pour les exceptions souhaitées, le cas échéant. Mettez à jour la logique de création de ProxyFactory avec ExceptionSerializationTechnique et la liste des classes IExceptionConvertor. Mettre à niveau le client existant pour appliquer les modifications de sérialisation des exceptions

Étapes suivantes