Omówienie serializacji wyjątków komunikacji zdalnie

Serializacja oparta na binaryFormatter nie jest bezpieczna, więc nie używaj klasy BinaryFormatter do przetwarzania danych. Aby uzyskać więcej informacji na temat implikacji zabezpieczeń, zobacz Deserializacja ryzyka w użyciu klasy BinaryFormatter i powiązanych typów.

Usługa Azure Service Fabric używa klasy BinaryFormatter do serializacji wyjątków. Począwszy od usługi ServiceFabric w wersji 9.0, serializacja oparta na kontrakcie danych dla wyjątków komunikacji równorzędnej jest dostępna jako funkcja zgody. Zalecamy, aby wybrać serializacji wyjątków komunikacji zdalnie usługi DataContract, wykonując kroki opisane w tym artykule.

Obsługa serializacji wyjątków komunikacji zdalnie opartej na programie BinaryFormatter zostanie wycofana w przyszłości.

Włączanie serializacji kontraktu danych dla wyjątków komunikacji zdalniej

Uwaga

Serializacja kontraktu danych dla wyjątków komunikacji wirtualnej jest dostępna tylko w przypadku usług komunikacji zdalniej w wersji 2/V2_1.

Aby włączyć serializacji kontraktu danych dla wyjątków komunikacji zdalnie:

  1. Włącz serializację wyjątków remotingu dataContract po stronie usługi przy użyciu FabricTransportRemotingListenerSettings.ExceptionSerializationTechnique podczas tworzenia odbiornika komunikacji zdalniej.

    • Bezstanowa usługa

      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
      Aby włączyć serializację wyjątków remoting usługi DataContract w usłudze CreateServiceReplicaListeners() aktora, przesłoń przez rozszerzenie ActorService.

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

    Jeśli oryginalny wyjątek ma wiele poziomów wyjątków wewnętrznych, można kontrolować liczbę poziomów wyjątków wewnętrznych do serializacji przez ustawienie FabricTransportRemotingListenerSettings.RemotingExceptionDepth.

  2. Włącz serializacji wyjątków komunikacji zdalniej usługi DataContract na kliencie przy użyciu FabricTransportRemotingSettings.ExceptionDeserializationTechnique polecenia podczas tworzenia fabryki klienta.

    • Tworzenie elementu 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. Serializacja wyjątku komunikacji wirtualnej DataContract konwertuje wyjątek do obiektu transferu danych (DTO) po stronie usługi. Obiekt DTO jest konwertowany z powrotem na wyjątek po stronie klienta. Użytkownicy muszą zarejestrować się ExceptionConvertor , aby przekonwertować żądane wyjątki na obiekty DTO i na odwrót.

    Struktura implementuje konwertory dla następującej listy wyjątków. Jeśli kod usługi użytkownika zależy od wyjątków spoza poniższej listy do obsługi ponawiania prób i obsługi wyjątków, użytkownicy muszą zaimplementować i zarejestrować konwertery dla takich wyjątków.

    • Wszystkie wyjątki usługi Service Fabric pochodzące z System.Fabric.FabricException
    • Wyjątek SystemExceptions pochodzący z 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

Przykładowa implementacja konwertora po stronie usługi dla wyjątku niestandardowego

Poniższy przykład to implementacja referencyjna IExceptionConvertor po stronie usługi i klienta dla dobrze znanego typu wyjątku: CustomException.

  • Wyjątek 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 implementacja po stronie usługi :

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

Rzeczywisty wyjątek zaobserwowany podczas wykonywania wywołania komunikacji telefonicznej jest przekazywany jako dane wejściowe do metody TryConvertToServiceException. Jeśli typ wyjątku jest dobrze znany, TryConvertToServiceException należy przekonwertować oryginalny wyjątek na ServiceException i zwrócić go jako parametr wyjściowy. Wartość true powinna zostać zwrócona, jeśli oryginalny typ wyjątku jest dobrze znany, a oryginalny wyjątek zostanie pomyślnie przekonwertowany na ServiceException. W przeciwnym razie wartość to false.

Lista wyjątków wewnętrznych na bieżącym poziomie powinna zostać zwrócona przez .GetInnerExceptions()

  • IExceptionConvertor implementacja po stronie klienta :

    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 parametr jest przekazywany jako parametr do TryConvertFromServiceException parametru wraz z przekonwertowanym innerException[s]elementem . Jeśli rzeczywisty typ wyjątku, ServiceException.ActualExceptionType, jest znany, konwertujący powinien utworzyć rzeczywisty obiekt wyjątku z ServiceException i innerException[s].

  • IExceptionConvertor rejestracja po stronie usługi :

    Aby rejestrować konwertery, należy je zastąpić, CreateServiceInstanceListeners a lista IExceptionConvertor klas musi zostać przekazana podczas tworzenia RemotingListener wystąpienia.

    • Bezstanowa usługa

      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 rejestracja po stronie klienta :

    Aby zarejestrować konwertery, należy przekazać listę IExceptionConvertor klas podczas tworzenia ClientFactory wystąpienia.

    • Tworzenie elementu ServiceProxyFactory

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

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

Uwaga

Jeśli struktura znajdzie konwerter dla wyjątku, przekonwertowany (rzeczywisty) wyjątek jest opakowany wewnątrz AggregateException i jest zgłaszany do interfejsu API komunikacji wirtualnej (proxy). Jeśli platforma nie może odnaleźć konwertera, to ServiceException, który zawiera wszystkie szczegóły rzeczywistego wyjątku, jest opakowany wewnątrz AggregateException i jest zgłaszany.

Uaktualnianie istniejącej usługi w celu włączenia serializacji kontraktu danych dla wyjątków komunikacji sieciowej

Aby uaktualnić istniejące usługi, należy wykonać następującą kolejność (najpierw usługa). Błąd wykonania tej kolejności może spowodować niewłaściwe zachowanie logiki ponawiania prób i obsługi wyjątków.

  1. Zaimplementuj klasy po stronie ExceptionConvertorusługi dla żądanych wyjątków, jeśli istnieją. Zaktualizuj logikę rejestracji odbiornika komunikacji zdalnie za pomocą polecenia ExceptionSerializationTechnique i listę IExceptionConvertorklas. Uaktualnij istniejącą usługę, aby zastosować zmiany serializacji wyjątków.

  2. Zaimplementuj klasy po stronie ExceptionConvertorklienta dla żądanych wyjątków, jeśli istnieją. Zaktualizuj logikę tworzenia serwera ProxyFactory za pomocą polecenia ExceptionSerializationTechnique i listę IExceptionConvertor klas. Uaktualnij istniejącego klienta, aby zastosować zmiany serializacji wyjątków.

Następne kroki