リモート処理例外のシリアル化の概要

BinaryFormatter ベースのシリアル化は安全ではないので、データ処理には BinaryFormatter を使わないでください。 セキュリティへの影響について詳しくは、「BinaryFormatter および関連する型を使用するときの逆シリアル化のリスク」をご覧ください。

Azure Service Fabric では、例外のシリアル化に BinaryFormatter が使われていました。 ServiceFabric v9.0 以降では、リモート処理例外に対するデータ コントラクト ベースのシリアル化をオプトイン機能として利用できます。 この記事の手順に従って、DataContract リモート処理例外のシリアル化を選ぶことをお勧めします。

BinaryFormatter ベースのリモート処理例外のシリアル化は、今後サポートされなくなります。

リモート処理例外でデータ コントラクトのシリアル化を有効にする

Note

リモート処理例外でのデータ コントラクトのシリアル化は、リモート処理 V2/V2_1 サービスでのみ実行できます。

リモート処理例外でデータ コントラクトのシリアル化を有効にするには:

  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
      アクター サービスで 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 を設定することで、シリアル化する内部例外のレベル数を制御できます。

  2. クライアント ファクトリの作成時に 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);
      });
      
  3. DataContract リモート処理例外のシリアル化では、例外がサービス側でデータ転送オブジェクト (DTO) に変換されます。 DTO は、クライアント側で例外に変換されます。 ユーザーは、目的の例外を DTO オブジェクトに変換するために (逆の場合も同様) ExceptionConvertor を登録する必要があります。

    フレームワークにより、次の一覧の例外に対するコンバーターが実装されます。 ユーザー サービス コードが再試行の実装と例外処理のために次の一覧以外の例外に依存する場合、ユーザーはそのような例外用のコンバーターを実装して登録する必要があります。

    • System.Fabric.FabricException から派生するすべての Service Fabric 例外
    • System.SystemException から派生する 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

カスタム例外のサービス側コンバーターの実装例

既知の例外の種類 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 に変換し、out パラメーターとして返す必要があります。 元の例外の種類がわかっていて、元の例外が 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 (プロキシ) でスローされます。 フレームワークによってコンバーターが検出されない場合は、実際の例外のすべての詳細を含む ServiceExceptionAggregateException 内でラップされ、スローされます。

既存のサービスをアップグレードして、リモート処理例外で DataContract シリアル化を有効にする

アップグレードするには、既存のサービスが以下の順序 ("サービス優先") になっている必要があります。 この順序に従っていない場合、再試行ロジックや例外処理で誤った動作が発生する可能性があります。

  1. サービス側で、目的の例外 (存在する場合) の ExceptionConvertor クラスを実装します。 ExceptionSerializationTechnique でのリモート処理リスナー登録ロジックと、IExceptionConvertor クラスのリストを更新します。 既存のサービスをアップグレードして、例外のシリアル化の変更を適用します。

  2. クライアント側で、目的の例外 (存在する場合) の ExceptionConvertor クラスを実装します。 ExceptionSerializationTechnique での ProxyFactory 作成ロジックと、IExceptionConvertor クラスのリストを更新します。 既存のクライアントをアップグレードして、例外のシリアル化の変更を適用します。

次のステップ