Übersicht über Remotingausnahmeserialisierung

BinaryFormatter-basierte Serialisierung ist nicht sicher, verwenden Sie BinaryFormatter daher nicht für die Datenverarbeitung. Weitere Informationen zu den Sicherheitsauswirkungen finden Sie unter Deserialisierungsrisiken bei der Verwendung von BinaryFormatter und verwandten Typen.

Service Fabric nutzte früher BinaryFormatter zum Serialisieren von Ausnahmen. Ab ServiceFabric v9.0 wird datenvertragbasierte Serialisierung für Remotingausnahmen als wählbare Option verfügbar gemacht. Es wird empfohlen, DataContract-Remotingausnahmeserialisierung zu aktivieren, indem Sie die Schritte in diesem Artikel ausführen.

Unterstützung für BinaryFormatter-basierte Remotingausnahmenserialisierung wird in Zukunft als veraltet markiert.

Aktivieren von Datenvertragsserialisierung für Remotingausnahmen

Hinweis

Datenvertragsserialisierung für Remotingausnahmen ist nur für V2/V2.1-Remotingdienste verfügbar.

So aktivieren Sie Datenvertragsserialisierung für Remotingausnahmen:

  1. Aktivieren Sie DataContract-Remotingausnahmeserialisierung auf der Dienstseite, indem Sie FabricTransportRemotingListenerSettings.ExceptionSerializationTechnique verwenden, während Sie den Remotinglistener erstellen.

    • 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
      Um DataContract-Remotingausnahmeserialisierung für den Actordienst zu aktivieren, überschreiben Sie CreateServiceReplicaListeners(), indem Sie ActorService erweitern.

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

    Wenn die ursprüngliche Ausnahme mehrere Ebenen innerer Ausnahmen aufweist, können Sie die Anzahl der Ebenen von inneren Ausnahmen, die serialisiert werden sollen, durch Festlegen von FabricTransportRemotingListenerSettings.RemotingExceptionDepth steuern.

  2. Aktivieren Sie DataContract-Remotingausnahmeserialisierung auf dem Client mithilfe von FabricTransportRemotingSettings.ExceptionDeserializationTechnique während des Erstellens der Clientfactory.

    • Erstellen von 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-Remotingausnahmeserialisierung konvertiert eine Ausnahme auf der Dienstseite in das Datenübertragungsobjekt (DTO). Das DTO wird auf der Clientseite zurück in eine Ausnahme konvertiert. Benutzer müssen ExceptionConvertor registrieren, um die gewünschten Ausnahmen in DTO-Objekte zu konvertieren und umgekehrt.

    Das Framework implementiert Konverter für die folgende Liste von Ausnahmen. Wenn der Benutzerdienstcode von Ausnahmen außerhalb der folgenden Liste für die Wiederholungsimplementierung und Ausnahmebehandlung abhängt, müssen Benutzer Konverter für diese Ausnahmen implementieren und registrieren.

    • Alle von System.Fabric.FabricException abgeleiteten Service Fabric-Ausnahmen
    • Von System.SystemException abgeleitete SystemExceptions
      • 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

Beispielimplementierung eines dienstseitigen Konverters für eine benutzerdefinierte Ausnahme

Das folgende Beispiel ist eine Referenzimplementierung von IExceptionConvertor auf der Dienst- und Clientseite für einen bekannten Ausnahmetyp: 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-Implementierung auf der Dienstseite:

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

Die tatsächliche Ausnahme, die während der Ausführung des Remotingaufrufs beobachtet wird, wird als Eingabe an TryConvertToServiceException übergeben. Wenn der Typ der Ausnahme eine bekannt ist, sollte TryConvertToServiceException die ursprüngliche Ausnahme in ServiceException konvertieren und als Out-Parameter zurückgeben. Der Wert TRUE sollte zurückgegeben werden, wenn der ursprüngliche Ausnahmetyp bekannt ist und die ursprüngliche Ausnahme erfolgreich in eine ServiceException konvertiert wird. Andernfalls ist der Wert „false“.

Eine Liste der inneren Ausnahmen auf der aktuellen Ebene sollte von GetInnerExceptions() zurückgegeben werden.

  • IExceptionConvertor-Implementierung auf der Clientseite:

    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 wird als Parameter zusammen mit der konvertierten innerException[s] an TryConvertFromServiceException übergeben. Wenn der Typ der tatsächlichen Ausnahme (ServiceException.ActualExceptionType) bekannt ist, sollte der Konverter ein tatsächliches Ausnahmeobjekt aus der ServiceException und den innerException[s] erstellen.

  • IExceptionConvertor-Registrierung auf der Dienstseite:

    Um Konvertierungen zu registrieren, muss CreateServiceInstanceListeners überschrieben werden, und die Liste der IExceptionConvertor-Klassen muss beim Erstellen der RemotingListener-Instanz übergeben werden.

    • 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-Registrierung auf der Clientseite:

    Um Konverter zu registrieren, muss die Liste der IExceptionConvertor-Klassen beim Erstellen der ClientFactory-Instanz übergeben werden.

    • Erstellen von ServiceProxyFactory

      var serviceProxyFactory = new ServiceProxyFactory(
      (callbackClient) =>
      {
         return new FabricTransportServiceRemotingClientFactory(
             new FabricTransportRemotingSettings
             {
                 ExceptionDeserializationTechnique = FabricTransportRemotingSettings.ExceptionDeserialization.Default,
             },
             callbackClient,
             exceptionConvertors: new[]
             {
                 new CustomConvertorClient(),
             });
      });
      
    • Erstellen von ActorProxyFactory

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

Hinweis

Wenn das Framework den Konverter für die Ausnahme findet, wird die konvertierte (tatsächliche) Ausnahme von AggregateException umschlossen und an der Remoting-API (Proxy) ausgelöst. Wenn das Framework den Konverter nicht finden konnte, wird die ServiceException, die alle Details der tatsächlichen Ausnahme enthält, von AggregateException umschlossen und ausgelöst.

Upgrade eines vorhandenen Diensts zum Aktivieren von Datenvertragsserialisierung für Remotingausnahmen

Vorhandene Dienste müssen die folgende Reihenfolge beachten (Dienst zuerst), um das Upgrade zu erhalten. Die Nichteinhaltung der Reihenfolge kann zu Fehlverhalten in der Wiederholungslogik und der Ausnahmebehandlung führen.

  1. Implementieren Sie die dienstseitigenExceptionConvertor-Klassen für die gewünschten Ausnahmen (falls vorhanden). Aktualisieren Sie die Registrierungslogik des Remotinglisteners mit ExceptionSerializationTechnique und der Liste der IExceptionConvertor-Klassen. Führen Sie ein Upgrade des vorhandenen Diensts aus, um die Serialisierungsänderungen der Ausnahme anzuwenden.

  2. Implementieren Sie die clientseitigenExceptionConvertor-Klassen für die gewünschten Ausnahmen (falls vorhanden). Aktualisieren Sie die ProxyFactory-Erstellungslogik mit ExceptionSerializationTechnique und einer Liste mit IExceptionConvertor-Klassen. Führen Sie ein Upgrade des vorhandenen Clients aus, um die Ausnahmeserialisierungsänderungen anzuwenden.

Nächste Schritte