다음을 통해 공유


원격 예외 직렬화 개요

BinaryFormatter 기반 직렬화는 안전하지 않으므로 데이터 처리에 BinaryFormatter를 사용하지 마세요. 보안에 미치는 영향에 대한 자세한 내용은 BinaryFormatter 및 관련 형식을 사용할 때의 역직렬화 위험을 참조하세요.

Azure Service Fabric은 예외를 직렬화하기 위해 BinaryFormatter를 사용했습니다. ServiceFabric v9.0부터 원격 예외를 위한 데이터 계약 기반 serialization이 옵트인 기능으로 제공됩니다. 이 문서의 단계에 따라 DataContract 원격 예외 serialization을 선택하는 것이 좋습니다.

BinaryFormatter 기반 원격 예외 serialization에 대한 지원은 향후 더 이상 사용되지 않습니다.

원격 예외에 대한 데이터 계약 serialization을 사용하도록 설정

참고 항목

원격 예외에 대한 데이터 계약 serialization은 원격 V2/V2_1 서비스에만 사용할 수 있습니다.

원격 예외에 대한 데이터 계약 serialization을 사용하도록 설정하려면 다음을 수행합니다.

  1. 원격 수신기를 만드는 동안 FabricTransportRemotingListenerSettings.ExceptionSerializationTechnique을 사용하여 서비스 측에서 DataContract 원격 예외 serialization을 사용하도록 설정합니다.

    • 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 원격 예외 serialization을 사용하도록 설정하려면 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 원격 예외 serialization을 사용하도록 설정합니다.

    • 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 원격 예외 serialization은 예외를 서비스 쪽의 DTO(데이터 전송 개체)로 변환합니다. DTO는 클라이언트 쪽에서 예외로 다시 변환됩니다. 사용자는 원하는 예외를 DTO 개체로 또는 그 반대로 변환하려면 ExceptionConvertor를 등록해야 합니다.

    프레임워크는 다음 예외 목록에 대한 변환기를 구현합니다. 사용자 서비스 코드가 다시 시도 구현, 예외 처리 등을 위해 다음 목록 외부의 예외에 의존하는 경우 사용자는 이러한 예외에 대한 변환기를 구현 및 등록해야 합니다.

    • System.Fabric.FabricException에서 파생된 모든 Service Fabric 예외
    • System.SystemException에서 파생된 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

사용자 지정 예외에 대한 서비스 측 변환기의 샘플 구현

다음 예제는 잘 알려진 예외 형식 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)이 알려진 형식인 경우 변환기는 ServiceExceptioninnerException[s]에서 실제 예외 개체를 만들어야 합니다.

  • 서비스 측에서 IExceptionConvertor 등록:

    변환기를 등록하려면 RemotingListener 인스턴스를 만드는 동안 CreateServiceInstanceListeners를 재정의하고 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(프록시)에서 throw됩니다. 프레임워크가 변환기를 찾지 못하면 실제 예외의 모든 세부 정보를 포함하는 ServiceExceptionAggregateException 내부에 래핑되고 throw됩니다.

원격 예외에 대한 데이터 계약 serialization을 사용하도록 설정하도록 기존 서비스 업그레이드

기존 서비스를 업그레이드하려면 다음 순서(서비스 우선)를 따라야 합니다. 이 순서를 따르지 않으면 다시 시도 논리 및 예외 처리에서 오작동이 발생할 수 있습니다.

  1. 원하는 예외에 대해 서비스ExceptionConvertor 클래스를 구현합니다(있는 경우). ExceptionSerializationTechniqueIExceptionConvertor 클래스 목록을 사용하여 원격 수신기 등록 논리를 업데이트합니다. 예외 serialization 변경 내용을 적용하려면 기존 서비스를 업그레이드합니다.

  2. 원하는 예외에 대해 클라이언트ExceptionConvertor 클래스를 구현합니다(있는 경우). ExceptionSerializationTechniqueIExceptionConvertor 클래스 목록을 사용하여 ProxyFactory 만들기 논리를 업데이트합니다. 예외 serialization 변경 내용을 적용하려면 기존 클라이언트를 업그레이드합니다.

다음 단계