远程处理异常序列化概述
基于 BinaryFormatter 的序列化不安全,因此不要使用 BinaryFormatter 进行数据处理。 有关安全影响的详细信息,请参阅 BinaryFormatter 和相关类型的使用中的反序列化风险。
Azure Service Fabric 使用 BinaryFormatter 序列化异常。 从 ServiceFabric v9.0 开始,用于远程处理异常的基于数据协定的序列化便作为可选功能提供。 建议按照本文中的步骤选择 DataContract 远程处理异常序列化。
未来将弃用对基于 BinaryFormatter 的远程处理异常序列化的支持。
启用用于远程处理异常的数据协定序列化
注意
用于远程处理异常的数据协定序列化仅适用于远程处理 V2/V2_1 服务。
启用用于远程处理异常的数据协定序列化:
在创建远程处理侦听器时,使用
FabricTransportRemotingListenerSettings.ExceptionSerializationTechnique
在服务端启用 DataContract 远程处理异常序列化。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
若要在 ActorService 上启用 DataContract 远程处理异常序列化,请通过扩展ActorService
替代CreateServiceReplicaListeners()
。protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners() { return new List<ServiceReplicaListener> { new ServiceReplicaListener(_ => { return new FabricTransportActorServiceRemotingListener( this, new FabricTransportRemotingListenerSettings { ExceptionSerializationTechnique = FabricTransportRemotingListenerSettings.ExceptionSerialization.Default, }); }, "MyActorServiceEndpointV2") }; }
如果原始异常具有多个级别的内部异常,可以通过设置
FabricTransportRemotingListenerSettings.RemotingExceptionDepth
来控制要序列化的内部异常的级别数。在创建客户端工厂时,使用
FabricTransportRemotingSettings.ExceptionDeserializationTechnique
在客户端启用 DataContract 远程处理异常序列化。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); });
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
- 所有 Service Fabric 异常(派生自
自定义异常的服务端转换器的示例实现
下面示例是已知异常类型 CustomException
在“服务”和“客户”端的参考 IExceptionConvertor
实现。
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
并将其作为输出参数返回。 如果原始异常类型为已知类型,并且原始异常已成功转换为 ServiceException
,则应返回 true 值。 否则,该值为 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
作为参数与转换的 innerException[s]
一起传递给 TryConvertFromServiceException
。 如果实际异常类型 ServiceException.ActualExceptionType
为已知类型,则转换器应从 ServiceException
和 innerException[s]
创建实际异常对象。
“服务”端的
IExceptionConvertor
注册:若要注册转换程序,必须重写
CreateServiceInstanceListeners
,并且必须在创建RemotingListener
实例时传递IExceptionConvertor
类列表。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
注册:若要注册转换程序,必须在创建
ClientFactory
实例时传递IExceptionConvertor
类列表。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
中并引发。
升级现有服务以启用用于远程处理异常的数据协定序列化
现有服务必须遵循以下顺序(“服务优先”)进行升级。 未能按照以下顺序操作可能会导致重试逻辑和异常处理发生错误行为。
为所需的异常(如果有)实现“服务”端
ExceptionConvertor
类。 采用ExceptionSerializationTechnique
和IExceptionConvertor
类列表更新远程处理侦听器注册逻辑。 升级现有服务以应用异常序列化更改。为所需的异常(如果有)实现“客户”端
ExceptionConvertor
类。 采用ExceptionSerializationTechnique
和IExceptionConvertor
类列表更新 ProxyFactory 创建逻辑。 升级现有客户端以应用异常序列化更改。