Поделиться через


Обзор сериализации исключений удаленного взаимодействия

Сериализация на основе BinaryFormatter не является безопасной, поэтому не используйте BinaryFormatter для обработки данных. Дополнительные сведения о последствиях безопасности см. в разделе Риски десериализации в использовании BinaryFormatter и связанных типов.

В Service Fabric для сериализации исключений использовался BinaryFormatter. Начиная с ServiceFabric версии 9.0 сериализация на основе контракта данных для исключений удаленного взаимодействия предоставляется в качестве выбираемой функции. Рекомендуется выбрать сериализацию исключений удаленного взаимодействия DataContract, выполнив действия, описанные в этой статье.

Поддержка сериализации исключений удаленного взаимодействия на основе BinaryFormatter будет прекращена в будущем.

Включение сериализации данных контракта для исключений удаленного взаимодействия

Примечание.

Сериализация контракта данных для исключений удаленного взаимодействия доступна только для служб удаленного взаимодействия версии 2/V2_1.

Включение сериализации данных контракта для исключений удаленного взаимодействия:

  1. Включите сериализацию исключений удаленного взаимодействия контракта данных на стороне Службы, используя FabricTransportRemotingListenerSettings.ExceptionSerializationTechnique при создании прослушивателя удаленного взаимодействия.

    • 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
      Чтобы включить сериализацию исключений удаленного взаимодействия DataContract в ActorService, замените CreateServiceReplicaListeners() путем расширения ActorService.

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

    Если исходное исключение имеет несколько уровней внутренних исключений, можно управлять количеством уровней внутренних исключений, для которых выполняется сериализация, с помощью параметра FabricTransportRemotingListenerSettings.RemotingExceptionDepth.

  2. Включение сериализации исключений удаленного взаимодействия DataContract на Клиенте с помощью FabricTransportRemotingSettings.ExceptionDeserializationTechnique при создании фабрики клиентов.

    • Создание 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. Сериализация удаленного взаимодействия DataContract преобразует исключение в объект передачи данных (DTO) на стороне службы. DTO преобразуется обратно в исключение на стороне клиента. Пользователям необходимо зарегистрировать ExceptionConvertor для преобразования требуемых исключений в объекты DTO и наоборот.

    Платформа реализует преобразователи для следующего списка исключений. Если код пользовательской службы зависит от исключений за пределами приведенного ниже списка для реализации повторных попыток, обработки исключений и т. д., пользователю необходимо реализовать и зарегистрировать преобразователи для таких исключений.

    • Все исключения Service Fabric, производные от System.Fabric.FabricException
    • SystemExceptions, производные от 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

Пример реализации преобразователя на стороне службы для пользовательского исключения

Ниже приведен пример реализации IExceptionConvertor на стороне Службы и Клиента для известного типа исключения, 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 на стороне Службы:

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

Фактическое исключение, наблюдаемое во время выполнения вызова удаленного взаимодействия, передается в качестве входных данных в TryConvertToServiceException. Если тип исключения является хорошо известным, то TryConvertToServiceException должен преобразовать исходное исключение в ServiceException и вернуть его в качестве выходного параметра. Значение true должно быть возвращено, если исходный тип исключения хорошо известен, а исходное исключение успешно преобразовано в ServiceException. В противном случае значение равно false.

GetInnerExceptions() должен возвращать список внутренних исключений на текущем уровне.

  • реализация IExceptionConvertor на стороне Клиента:

    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 передается в качестве параметра в TryConvertFromServiceException вместе с преобразованным innerException[s]. Если фактический тип исключения, ServiceException.ActualExceptionType, является известным, то преобразователь должен создать фактический объект исключения из ServiceException и innerException[s].

  • Регистрация IExceptionConvertor на стороне Службы:

    Чтобы зарегистрировать преобразователи, CreateServiceInstanceListeners необходимо переопределить и передать список IExceptionConvertor классов во время создания экземпляра RemotingListener.

    • Служба без отслеживания состояния

      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 на стороне клиента:

    Чтобы зарегистрировать преобразователи, необходимо передать список IExceptionConvertor классов при создании экземпляра ClientFactory.

    • Создание ServiceProxyFactory

      var serviceProxyFactory = new ServiceProxyFactory(
      (callbackClient) =>
      {
         return new FabricTransportServiceRemotingClientFactory(
             new FabricTransportRemotingSettings
             {
                 ExceptionDeserializationTechnique = FabricTransportRemotingSettings.ExceptionDeserialization.Default,
             },
             callbackClient,
             exceptionConvertors: new[]
             {
                 new CustomConvertorClient(),
             });
      });
      
    • Создание ActorProxyFactory

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

Примечание.

Если платформа находит преобразователь для исключения, то преобразованное (фактическое) исключение переносится в AggregateException и выдается в API удаленного взаимодействия (прокси). Если платформе не удается найти преобразователь, то ServiceException, содержащее все сведения о фактическом исключении, переносится в AggregateException и вызывается.

Обновление существующей службы для включения сериализации данных контракта для исключений удаленных взаимодействий

Для обновления существующие службы должны быть указаны в следующем порядке (Сначала служба). Если этот порядок не соблюдается, это может привести к неправильному выполнению логики повторных попыток и обработке исключений.

  1. Реализуйте классы на стороне Службы ExceptionConvertor для требуемых исключений (если таковые есть). Обновите логику регистрации прослушивателя удаленного взаимодействия с помощью ExceptionSerializationTechnique и списка IExceptionConvertor классов. Обновление существующей службы для применения изменений сериализации исключений.

  2. Реализуйте классы на стороне клиентаExceptionConvertor для требуемых исключений (если таковые есть). Обновите логику создания ProxyFactory с помощью ExceptionSerializationTechnique и списка IExceptionConvertor классов. Обновите существующий клиент для применения изменений сериализации исключений.

Следующие шаги