Partekatu honen bidez:


Información general sobre la serialización de excepciones de comunicación remota

La serialización basada en BinaryFormatter no es segura, por lo que no use BinaryFormatter para el procesamiento de datos. Para más información sobre las implicaciones de seguridad, consulte Riesgos de deserialización en el uso de BinaryFormatter y tipos relacionados.

Azure Service Fabric utilizó BinaryFormatter para serializar excepciones. A partir de ServiceFabric v9.0, la serialización basada en el contrato de datos para excepciones de comunicación remota está disponible como una característica opcional. Se recomienda optar por la serialización de excepciones de comunicación remota de DataContract, siguiendo los pasos de este artículo.

La compatibilidad con la serialización de excepciones de comunicación remota basada en BinaryFormatter quedará en desuso en el futuro.

Habilitar la serialización de contratos de datos para excepciones de comunicación remota

Nota:

La serialización de contratos de datos para excepciones de comunicación remota solo está disponible para los servicios de comunicación remota V2/V2_1.

Para habilitar la serialización de contratos de datos para excepciones de comunicación remota:

  1. Habilite la serialización de excepciones de comunicación remota de DataContract en el lado del Servicio mediante la instrucción FabricTransportRemotingListenerSettings.ExceptionSerializationTechnique al crear el agente de escucha de comunicación remota.

    • 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
      Para habilitar la serialización de excepciones de comunicación remota de DataContract en el servicio del actor, invalide CreateServiceReplicaListeners() mediante la ampliación de ActorService.

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

    Si la excepción original tiene varios niveles de excepciones internas, puede controlar el número de niveles de las excepciones internas que se van a serializar estableciendo FabricTransportRemotingListenerSettings.RemotingExceptionDepth.

  2. Habilite la serialización de excepciones de comunicación remota de DataContract en el Cliente mediante la instrucción FabricTransportRemotingSettings.ExceptionDeserializationTechnique al crear la fábrica de cliente.

    • Creación 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 serialización de excepciones de comunicación remota de DataContract convierte una excepción al objeto de transferencia de datos (DTO) en el lado del servicio. El DTO se convierte de nuevo en una excepción en el lado del cliente. Los usuarios deben registrar ExceptionConvertor para convertir las excepciones deseadas en objetos DTO y viceversa.

    El marco implementa los convertidores en la siguiente lista de excepciones. Si el código de servicio del usuario depende de excepciones que no están en la siguiente lista para la implementación de reintentos y el control de excepciones, los usuarios deben implementar y registrar los convertidores para dichas excepciones.

    • Todas las excepciones de Service Fabric derivadas de System.Fabric.FabricException
    • Excepciones del sistema derivadas 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

Implementación de muestra del convertidor del lado del servicio pq4q una excepción personalizada

El ejemplo siguiente muestra la implementación de referencia IExceptionConvertor en el lado del Servicio y del Cliente para un tipo de excepción muy conocido: 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; }
    }
    
  • Implementación de IExceptionConvertor en el lado del Servicio:

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

La excepción como tal observada durante la ejecución de la llamada de comunicación remota se pasa como entrada a TryConvertToServiceException. Si el tipo de excepción es uno bien conocido, TryConvertToServiceException debe convertir la excepción original en ServiceException y devolverla como parámetro de salida. Se debe devolver un valor “true” si el tipo de excepción original es conocido y si la excepción original se convierte correctamente en ServiceException. En caso contrario, el valor es false.

Una lista de excepciones internas en el nivel actual debe devolverse mediante GetInnerExceptions().

  • Implementación de IExceptionConvertor en el lado del Cliente:

    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 se pasa como parámetro a TryConvertFromServiceException junto con innerException[s] convertido. Si el tipo de excepción como tal, ServiceException.ActualExceptionType, es conocido, el convertidor debe crear un objeto de excepción como tal a partir de ServiceException y innerException[s].

  • Registro de IExceptionConvertor en el lado del Servicio:

    Para registrar los convertidores, CreateServiceInstanceListeners se debe invalidar y se debe pasar la lista de clases IExceptionConvertor mientras crea la instancia 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")
          };
      }
      
  • Registro de IExceptionConvertor en el lado del Cliente:

    Para registrar los convertidores, se debe pasar la lista de clases IExceptionConvertor mientras crea la instancia ClientFactory.

    • Creación de ServiceProxyFactory

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

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

Nota

Si el marco encuentra el convertidor para la excepción, la excepción convertida como tal se ajusta dentro de AggregateException y se lanza a la API de comunicación remota (proxy). Si el marco no encuentra el convertidor, entonces ServiceException, que contiene todos los detalles de la excepción como tal, se ajusta dentro de AggregateException y se lanza.

Actualice un servicio existente para habilitar la serialización de contrato de datos para excepciones de comunicación remota

Los servicios existentes deben seguir el orden siguiente (Primero el servicio) para actualizarse. Si no se sigue este orden, podría producirse un error de comportamiento en la lógica de reintentos y en el control de excepciones.

  1. Del lado del Servicio, implemente las clases ExceptionConvertor para las excepciones deseadas, si las hay. Actualice la lógica de registro del agente de escucha de comunicación remota con ExceptionSerializationTechnique y la lista de clases IExceptionConvertor. Actualice el servicio existente para aplicar los cambios de serialización de excepciones.

  2. Del lado del Cliente, implemente las clases ExceptionConvertor para las excepciones deseadas, si las hay. Actualice la lógica de creación de ProxyFactory con ExceptionSerializationTechnique y la lista de clases IExceptionConvertor. Actualice el cliente existente para aplicar los cambios de serialización de excepciones.

Pasos siguientes