Visão geral da serialização de exceções remotas
A serialização baseada em BinaryFormatter não é segura, portanto, não use BinaryFormatter para processamento de dados. Para obter mais informações sobre as implicações de segurança, consulte Riscos de desserialização no uso de BinaryFormatter e tipos relacionados.
O Azure Service Fabric usou BinaryFormatter para serializar exceções. A partir do ServiceFabric v9.0, a serialização baseada em contrato de dados para exceções de comunicação remota está disponível como um recurso de aceitação. Recomendamos que você opte pela serialização de exceção remota DataContract seguindo as etapas neste artigo.
O suporte para serialização de exceção de comunicação remota baseada em BinaryFormatter será preterido no futuro.
Habilitar a serialização de contrato de dados para exceções de comunicação remota
Nota
A serialização de contrato de dados para exceções de 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 de comunicação remota:
Habilite a serialização de exceção remota DataContract no lado Serviço usando
FabricTransportRemotingListenerSettings.ExceptionSerializationTechnique
enquanto cria o ouvinte remoto.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 remota DataContract no serviço ator, substituaCreateServiceReplicaListeners()
estendendoActorService
o .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 serializadas pela configuração
FabricTransportRemotingListenerSettings.RemotingExceptionDepth
.Habilite a serialização de exceção remota DataContract no cliente usando
FabricTransportRemotingSettings.ExceptionDeserializationTechnique
enquanto você cria a fábrica do 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 remota DataContract converte uma exceção para o objeto de transferência de dados (DTO) no lado do serviço. O DTO é convertido novamente em uma exceção no lado do cliente. Os usuários precisam se registrar
ExceptionConvertor
para converter as exceções desejadas em objetos DTO e vice-versa.A estrutura implementa conversores para a seguinte lista de exceções. Se o código de serviço do usuário depender de exceções fora da lista a seguir para implementação de novas tentativas e tratamento de exceções, os usuários precisarão 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
Exemplo de implementação de um conversor do lado do serviço para uma exceção personalizada
O exemplo a seguir é a implementação de referência IExceptionConvertor
no lado Serviço e Cliente para um tipo de exceção bem conhecido, 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
implementação 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 remota é passada como entrada para TryConvertToServiceException
. Se o tipo de exceção for bem conhecido, TryConvertToServiceException
deve converter a exceção original e ServiceException
devolvê-la como um parâmetro out. Um valor verdadeiro deve ser retornado se o tipo de exceção original for conhecido e a exceção original for convertida com êxito em ServiceException
. Caso contrário, o valor é false.
Uma lista de exceções internas no nível atual deve ser retornada por GetInnerExceptions()
.
IExceptionConvertor
implementação do 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 convertido innerException[s]
. Se o tipo de exceção real, ServiceException.ActualExceptionType
, for conhecido, o conversor deverá criar um objeto de exceção real de ServiceException
e innerException[s]
.
IExceptionConvertor
registo no lado do Serviço :Para registrar conversores,
CreateServiceInstanceListeners
deve ser substituído e a lista deIExceptionConvertor
classes deve ser passada enquanto você cria aRemotingListener
instância.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
registo do lado do Cliente :Para registrar conversores, a lista de
IExceptionConvertor
classes deve ser passada enquanto você cria aClientFactory
instância.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(), }); });
Nota
Se a estrutura encontrar o conversor para a exceção, a exceção convertida (real) será encapsulada dentro AggregateException
e será lançada na API de comunicação remota (proxy). Se a estrutura não conseguir encontrar o conversor, então ServiceException
, que contém todos os detalhes da exceção real, é encapsulado dentro AggregateException
e é lançado.
Atualizar um serviço existente para habilitar a serialização de contrato de dados para exceções de comunicação remota
Os serviços existentes devem seguir a seguinte ordem (Serviço primeiro) para atualizar. O não cumprimento dessa ordem pode resultar em mau comportamento na lógica de repetição e no tratamento de exceções.
Implemente as classes do lado
ExceptionConvertor
do serviço para as exceções desejadas, se houver. Atualize a lógica de registro do ouvinte remoto comExceptionSerializationTechnique
e a lista deIExceptionConvertor
classes. Atualize o serviço existente para aplicar as alterações de serialização de exceção.Implemente as classes do lado
ExceptionConvertor
do cliente para as exceções desejadas, se houver. Atualize a lógica de criação do ProxyFactory comExceptionSerializationTechnique
e a lista deIExceptionConvertor
classes. Atualize o cliente existente para aplicar as alterações de serialização de exceção.