Visão geral da serialização de exceção na comunicação remota
A serialização baseada em BinaryFormatter não é segura, portanto, não use o BinaryFormatter para processamento de dados. Para obter mais informações sobre as implicações de segurança, consulte Riscos de desserialização no uso do BinaryFormatter e tipos relacionados.
O Azure Service Fabric usava o BinaryFormatter para serializar exceções. A partir do ServiceFabric v9.0, a serialização baseada em contrato de dados para exceções na comunicação remota está disponibilizada como um recurso de aceitação. Recomendamos que você opte pela serialização de exceção de comunicação remota do DataContract seguindo as etapas deste artigo.
O suporte para serialização de exceção na comunicação remota baseada no BinaryFormatter será preterido no futuro.
Habilitar a serialização de contrato de dados para exceções na comunicação remota
Observação
A serialização de contrato de dados para exceções na comunicação remota só está disponível para serviços de comunicação remota V2/V2_1.
Para habilitar a serialização de contrato de dados para exceções na comunicação remota:
Habilite a serialização de exceção na comunicação remota do DataContract no lado do Serviço usando
FabricTransportRemotingListenerSettings.ExceptionSerializationTechnique
ao criar o ouvinte de comunicação 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 a serialização de exceção na comunicação remota do DataContract no serviço de ator, substituaCreateServiceReplicaListeners()
estendendoActorService
.protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners() { return new List<ServiceReplicaListener> { new ServiceReplicaListener(_ => { return new FabricTransportActorServiceRemotingListener( this, new FabricTransportRemotingListenerSettings { ExceptionSerializationTechnique = FabricTransportRemotingListenerSettings.ExceptionSerialization.Default, }); }, "MyActorServiceEndpointV2") }; }
Se a exceção original tiver vários níveis de exceções internas, você poderá controlar o número de níveis de exceções internas a serem serializados configurando
FabricTransportRemotingListenerSettings.RemotingExceptionDepth
.Habilitar a serialização de exceção na comunicação remota do DataContract no Cliente usando
FabricTransportRemotingSettings.ExceptionDeserializationTechnique
ao criar o alocador de cliente.Criação 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); });
A serialização de exceção de comunicação remota do DataContract converte uma exceção no DTO (objeto de transferência de dados) no lado do serviço. O DTO é convertido novamente em uma exceção no lado do cliente. Os usuários precisam registrar
ExceptionConvertor
para converter as exceções desejadas em objetos DTO e vice-versa.A estrutura implementa conversores para a lista de exceções a seguir. Se o código de serviço do usuário depender de exceções fora da lista a seguir para implementação de repetição e tratamento de exceção, o usuário precisará implementar e registrar conversores para essas exceções.
- Todas as exceções do Service Fabric derivadas de
System.Fabric.FabricException
- SystemExceptions 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
- Todas as exceções do Service Fabric derivadas de
Implementação de exemplo de um conversor do lado do serviço para uma exceção personalizada
O exemplo a seguir é uma implementação de referência IExceptionConvertor
no lado do Serviço e do Cliente para um tipo de exceção CustomException
bem conhecido.
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; } }
Implementação de
IExceptionConvertor
no lado do Serviço: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; } }
A exceção real observada durante a execução da chamada de comunicação remota é passada como entrada para TryConvertToServiceException
. Se o tipo da exceção for bem conhecido, TryConvertToServiceException
deve converter a exceção original em ServiceException
e retorná-la como um parâmetro de saída. Um valor true deverá ser retornado se o tipo de exceção original for bem conhecido e a exceção original for convertida com êxito em ServiceException
. Caso contrário, o valor será false.
Uma lista de exceções internas no nível atual deve ser retornada por GetInnerExceptions()
.
Implementação de
IExceptionConvertor
no lado do 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
é passado como um parâmetro para TryConvertFromServiceException
junto com o innerException[s]
convertido. Se o tipo de exceção real, ServiceException.ActualExceptionType
, for conhecido, o conversor deverá criar um objeto de exceção real do ServiceException
e innerException[s]
.
Registro de
IExceptionConvertor
no lado do Serviço:Para registrar conversores,
CreateServiceInstanceListeners
deve ser substituído e a lista de classesIExceptionConvertor
deve ser passada enquanto você cria a instânciaRemotingListener
.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
no lado do Cliente:Para registrar conversores, a lista de classes
IExceptionConvertor
deve ser passada enquanto você cria a instânciaClientFactory
.Criação de ServiceProxyFactory
var serviceProxyFactory = new ServiceProxyFactory( (callbackClient) => { return new FabricTransportServiceRemotingClientFactory( new FabricTransportRemotingSettings { ExceptionDeserializationTechnique = FabricTransportRemotingSettings.ExceptionDeserialization.Default, }, callbackClient, exceptionConvertors: new[] { new CustomConvertorClient(), }); });
Criação de ActorProxyFactory
var actorProxyFactory = new ActorProxyFactory( (callbackClient) => { return new FabricTransportActorRemotingClientFactory( new FabricTransportRemotingSettings { ExceptionDeserializationTechnique = FabricTransportRemotingSettings.ExceptionDeserialization.Default, }, callbackClient, exceptionConvertors: new[] { new CustomConvertorClient(), }); });
Observação
Se a estrutura encontrar o conversor para a exceção, a exceção convertida (real) será encapsulada em AggregateException
e lançada na API (proxy) de comunicação remota. Se a estrutura não encontrar o conversor, então ServiceException
, que contém todos os detalhes da exceção real, será encapsulado em AggregateException
e será gerado.
Atualizar um serviço existente para habilitar a serialização do contrato de dados para exceções de comunicação remota
Os serviços existentes devem seguir a ordem a seguir (Serviço primeiro) para atualizar. A falha em seguir a ordem a seguir pode resultar em mau comportamento na lógica de repetição e tratamento de exceção.
Implemente as classes
ExceptionConvertor
do lado do Serviço para as exceções desejadas, se houver. Atualize a lógica de registro do ouvinte de comunicação remota comExceptionSerializationTechnique
e a lista de classesIExceptionConvertor
. Atualize o serviço existente para aplicar as alterações de serialização de exceção.Implemente as classes
ExceptionConvertor
do lado do Cliente para as exceções desejadas, se houver. Atualize a lógica de criação do ProxyFactory comExceptionSerializationTechnique
e a lista de classesIExceptionConvertor
. Atualize o cliente existente para aplicar as alterações de serialização de exceção.