다음을 통해 공유


Orleans의 직렬화

Orleans에는 크게 두 가지 종류의 serialization이 사용됩니다.

  • 그레인 호출 직렬화: 그레인 사이에서 주고받는 개체를 직렬화하는 데 사용됩니다.
  • Grain Storage serialization: 스토리지 시스템과 개체를 직렬화하는 데 사용됩니다.

이 문서의 대부분은 Orleans에 포함된 직렬화 프레임워크를 사용한 그레인 호출(serialization)의 직렬화에 중점을 둡니다. Grain 스토리지 직렬 변환기 섹션에서는 그레인 스토리지 직렬화에 대해 설명합니다.

Orleans 직렬화 사용

Orleans 에는 .라고 하는 고급 및 확장 가능한 serialization 프레임워크가 Orleans포함되어 있습니다. serialization. Orleans에 포함된 serialization 프레임워크는 다음 목표를 충족하도록 설계되었습니다.

  • 고성능: 직렬 변환기는 성능을 위해 설계되고 최적화되었습니다. 자세한 내용은 이 프레젠테이션에서 확인할 수 있습니다.
  • 높은 충실도: 직렬 변환기는 제네릭, 다형성, 상속 계층, 객체 식별, 순환 그래프 등에 대한 지원을 포함하여 .NET의 형식 시스템을 대부분 충실하게 나타냅니다. 포인터는 프로세스 간에 이식할 수 없으므로 지원되지 않습니다.
  • 유연성: 서로게이트를 만들거나 System.Text.Json, Newtonsoft.JsonGoogle.Protobuf와 같은 외부 serialization 라이브러리를 위임하여 타사 라이브러리를 지원하도록 serializer를 사용자 지정할 수 있습니다.
  • 버전 허용 오차: 직렬 변환기를 사용하면 애플리케이션 유형이 시간이 지남에 따라 발전하여 다음을 지원할 수 있습니다.
    • 멤버 추가 및 제거
    • 서브클래스화
    • 숫자 확대 및 축소(예: int to/from long, float to/from double)
    • 형식 이름 바꾸기

형식의 고충실도 표현은 직렬화 도구에서 드물기 때문에, 일부 사항에 대한 추가 설명이 필요합니다.

  1. 동적 형식 및 임의 다형성: Orleans 곡물 호출에 전달된 형식에 제한을 적용하지 않고 실제 데이터 형식의 동적 특성을 유지 관리합니다. 예를 들어, grain 인터페이스의 메서드가 IDictionary를 수락하도록 선언되었지만, 런타임에 발신자가 SortedDictionary<TKey,TValue>를 전달하면, 수신자는 실제로 SortedDictionary를 받게 됩니다. 이는 "정적 계약"/grain 인터페이스가 이 동작을 명시하지 않았음에도 발생하는 일입니다.

  2. 객체의 동일성 유지: 동일한 객체가 여러 번 그레인 호출의 인수로 전달되거나 인수에서 두 번 이상 간접적으로 참조되는 경우, Orleans 는 그것을 한 번만 직렬화합니다. 수신기 쪽 Orleans 에서 모든 참조를 올바르게 복원하여 동일한 개체에 대한 두 포인터가 deserialization 후에도 동일한 개체를 가리키도록 합니다. 개체 ID 유지는 다음과 같은 시나리오에서 중요합니다. Imagine grain A는 100개의 항목이 있는 사전을 그레인 B로 보내고, 사전의 10개 키는 A 쪽에서 동일한 개체 obj를 가리킵니다. 개체 ID를 유지하지 않으면 B는 obj의 10개의 서로 다른 복제본을 가리키는 10개의 키가 포함된 100개 엔터티의 사전을 받게 됩니다. 개체 ID가 유지되면 B 측의 사전은 A 쪽과 똑같이 보이며, 이 10개의 키는 단일 개체 obj를 가리킵니다. .NET의 기본 문자열 해시 코드 구현은 프로세스별로 임의로 지정되므로 사전 및 해시 집합의 값 순서(예: )는 유지되지 않을 수 있습니다.

버전 호환성을 지원하려면 serializer가 직렬화할 형식 및 멤버를 명시적으로 지정해야 합니다. 우리는 이것을 가능한 한 고통스럽지 않은 것으로 만들기 위해 노력했습니다. 직렬화 가능한 모든 형식을 표시하여 형식 Orleans.GenerateSerializerAttribute 에 대한 serializer 코드를 생성하도록 지시 Orleans 합니다. 이 작업을 완료한 후에는 포함된 코드 수정을 사용하여 다음과 같이 형식의 직렬화 가능한 멤버에 필요한 Orleans.IdAttribute 항목을 추가할 수 있습니다.

포함 형식에 해당 멤버에 대한 IdAttribute가 포함되지 않은 경우 GenerateSerializerAttribute에 제안 및 적용되는 사용 가능한 코드 수정을 애니메이션으로 보여주는 이미지.

다음은 특성을 적용하는 방법을 보여 주는 Orleans의 직렬화 가능 형식의 예입니다.

[GenerateSerializer]
public class Employee
{
    [Id(0)]
    public string Name { get; set; }
}

Orleans 는 상속을 지원하고 계층의 개별 계층을 개별적으로 직렬화하여 고유한 멤버 ID를 가질 수 있도록 합니다.

[GenerateSerializer]
public class Publication
{
    [Id(0)]
    public string Title { get; set; }
}

[GenerateSerializer]
public class Book : Publication
{
    [Id(0)]
    public string ISBN { get; set; }
}

앞의 코드에서는 PublicationBook 모두 [Id(0)]를 멤버로 가지고 있음을 확인할 수 있으며, 이는 BookPublication에서 파생되었음에도 불구하고 그렇습니다. Orleans에서 멤버 식별자는 형식 전체가 아니라 상속 수준에서만 범위가 지정되므로, 이 방법을 사용하는 것이 권장됩니다. 멤버 Publication 를 독립적으로 추가 및 Book 제거할 수 있지만, 애플리케이션이 배포된 후에는 특별한 고려 없이 새 기본 클래스를 계층에 삽입할 수 없습니다.

또한 Orleans는 다음 형식 예와 같이 internal, privatereadonly 멤버를 사용하여 형식 직렬화를 지원합니다.

[GenerateSerializer]
public struct MyCustomStruct
{
    public MyCustom(int intProperty, int intField)
    {
        IntProperty = intProperty;
        _intField = intField;
    }

    [Id(0)]
    public int IntProperty { get; }

    [Id(1)] private readonly int _intField;
    public int GetIntField() => _intField;

    public override string ToString() => $"{nameof(_intField)}: {_intField}, {nameof(IntProperty)}: {IntProperty}";
}

기본적으로 Orleans 전체 이름을 인코딩하여 형식을 직렬화합니다. Orleans.AliasAttribute를 추가하여 이 설정을 재정의할 수 있습니다. 이렇게 하면 기본 클래스의 이름이 변경되거나 어셈블리가 이동되어도 영향을 받지 않는 이름을 사용하여 형식이 직렬화됩니다. 형식 별칭은 전역적으로 범위가 지정되며 애플리케이션에서 동일한 값을 가진 두 개의 별칭을 가질 수 없습니다. 제네릭 형식의 경우, 별칭 값에는 제네릭 매개 변수의 수와 그 앞에 백틱이 포함되어야 합니다. 예를 들어 MyGenericType<T, U>[Alias("mytype`2")]과 같은 별칭을 가질 수 있습니다.

record 형식 직렬화 중

레코드의 기본 생성자에 정의된 멤버에는 기본적으로 암시적 ID가 있습니다. 즉, Orleans는 record 형식 직렬화를 지원합니다. 즉, 이전 버전의 애플리케이션(롤링 업그레이드 시나리오)과 스토리지 및 스트림에서 해당 형식의 직렬화된 인스턴스와의 호환성이 손상되므로 이미 배포된 형식의 매개 변수 순서를 변경할 수 없습니다. 레코드 형식의 본문에 정의된 멤버는 ID를 기본 생성자 매개 변수와 공유하지 않습니다.

[GenerateSerializer]
public record MyRecord(string A, string B)
{
    // ID 0 won't clash with A in primary constructor as they don't share identities
    [Id(0)]
    public string C { get; init; }
}

기본 생성자 매개 변수를 직렬화 가능한 필드로 자동으로 포함하지 않으려면 .를 사용합니다 [GenerateSerializer(IncludePrimaryConstructorParameters = false)].

외래 형식을 직렬화하기 위한 대리자

경우에 따라 모든 권한이 없는 곡물 간에 형식을 전달해야 할 수 있습니다. 이러한 경우 애플리케이션 코드에서 사용자 지정 정의 형식으로 수동으로 변환하는 것은 실용적이지 않을 수 있습니다. Orleans는 이러한 상황에 대한 솔루션으로 대리자 유형을 제공합니다. 서로게이트는 대상 형식 대신 직렬화되며, 대상 형식으로 변환되거나 대상 형식에서 변환될 수 있는 기능을 갖추고 있습니다. 외래 형식 및 해당 서로게이트 및 변환기에 대한 다음 예제를 생각해 보겠습니다.

// This is the foreign type, which you do not have control over.
public struct MyForeignLibraryValueType
{
    public MyForeignLibraryValueType(int num, string str, DateTimeOffset dto)
    {
        Num = num;
        String = str;
        DateTimeOffset = dto;
    }

    public int Num { get; }
    public string String { get; }
    public DateTimeOffset DateTimeOffset { get; }
}

// This is the surrogate which will act as a stand-in for the foreign type.
// Surrogates should use plain fields instead of properties for better performance.
[GenerateSerializer]
public struct MyForeignLibraryValueTypeSurrogate
{
    [Id(0)]
    public int Num;

    [Id(1)]
    public string String;

    [Id(2)]
    public DateTimeOffset DateTimeOffset;
}

// This is a converter that converts between the surrogate and the foreign type.
[RegisterConverter]
public sealed class MyForeignLibraryValueTypeSurrogateConverter :
    IConverter<MyForeignLibraryValueType, MyForeignLibraryValueTypeSurrogate>
{
    public MyForeignLibraryValueType ConvertFromSurrogate(
        in MyForeignLibraryValueTypeSurrogate surrogate) =>
        new(surrogate.Num, surrogate.String, surrogate.DateTimeOffset);

    public MyForeignLibraryValueTypeSurrogate ConvertToSurrogate(
        in MyForeignLibraryValueType value) =>
        new()
        {
            Num = value.Num,
            String = value.String,
            DateTimeOffset = value.DateTimeOffset
        };
}

위의 코드에서

  • MyForeignLibraryValueType 는 사용 라이브러리에 정의된 컨트롤 외부의 형식입니다.
  • MyForeignLibraryValueTypeSurrogateMyForeignLibraryValueType에 대한 서로게이트 유형 매핑입니다.
  • RegisterConverterAttributeMyForeignLibraryValueTypeSurrogateConverter가 두 형식 간의 매핑을 위한 변환기로서 역할을 하도록 지정합니다. 클래스는 인터페이스를 IConverter<TValue,TSurrogate> 구현합니다.

Orleans 는 형식 계층 구조에서 형식의 serialization을 지원합니다(다른 형식에서 파생되는 형식). 외래 형식이 형식 계층 구조에 나타날 수 있는 경우(예: 고유한 형식 중 하나에 대한 기본 클래스로) 인터페이스를 Orleans.IPopulator<TValue,TSurrogate> 추가로 구현해야 합니다. 다음과 같은 예제를 참조하세요.

// The foreign type is not sealed, allowing other types to inherit from it.
public class MyForeignLibraryType
{
    public MyForeignLibraryType() { }

    public MyForeignLibraryType(int num, string str, DateTimeOffset dto)
    {
        Num = num;
        String = str;
        DateTimeOffset = dto;
    }

    public int Num { get; set; }
    public string String { get; set; }
    public DateTimeOffset DateTimeOffset { get; set; }
}

// The surrogate is defined as it was in the previous example.
[GenerateSerializer]
public struct MyForeignLibraryTypeSurrogate
{
    [Id(0)]
    public int Num;

    [Id(1)]
    public string String;

    [Id(2)]
    public DateTimeOffset DateTimeOffset;
}

// Implement the IConverter and IPopulator interfaces on the converter.
[RegisterConverter]
public sealed class MyForeignLibraryTypeSurrogateConverter :
    IConverter<MyForeignLibraryType, MyForeignLibraryTypeSurrogate>,
    IPopulator<MyForeignLibraryType, MyForeignLibraryTypeSurrogate>
{
    public MyForeignLibraryType ConvertFromSurrogate(
        in MyForeignLibraryTypeSurrogate surrogate) =>
        new(surrogate.Num, surrogate.String, surrogate.DateTimeOffset);

    public MyForeignLibraryTypeSurrogate ConvertToSurrogate(
        in MyForeignLibraryType value) =>
        new()
    {
        Num = value.Num,
        String = value.String,
        DateTimeOffset = value.DateTimeOffset
    };

    public void Populate(
        in MyForeignLibraryTypeSurrogate surrogate, MyForeignLibraryType value)
    {
        value.Num = surrogate.Num;
        value.String = surrogate.String;
        value.DateTimeOffset = surrogate.DateTimeOffset;
    }
}

// Application types can inherit from the foreign type, assuming they're not sealed
// since Orleans knows how to serialize it.
[GenerateSerializer]
public sealed class DerivedFromMyForeignLibraryType : MyForeignLibraryType
{
    public DerivedFromMyForeignLibraryType() { }

    public DerivedFromMyForeignLibraryType(
        int intValue, int num, string str, DateTimeOffset dto) : base(num, str, dto)
    {
        IntValue = intValue;
    }

    [Id(0)]
    public int IntValue { get; set; }
}

버전 관리 규칙

형식을 수정할 때 규칙 집합을 따르는 경우 버전 허용 오차가 지원됩니다. Protobuf(Google Protocol Buffers)와 같은 시스템에 익숙한 경우 이러한 규칙은 익숙할 것입니다.

복합 형식(classstruct)

  • 상속은 지원되지만 개체의 상속 계층 구조 수정은 지원되지 않습니다. 클래스의 기본 클래스를 추가, 변경 또는 제거할 수 없습니다.
  • 아래 숫자 섹션에 설명된 일부 숫자 형식을 제외하고 필드 형식 변경할 수 없습니다.
  • 상속 계층의 모든 지점에서 필드를 추가하거나 제거할 수 있습니다.
  • 필드 ID는 변경할 수 없습니다.
  • 필드 ID는 형식 계층 구조의 각 수준에 대해 고유해야 하지만 기본 클래스와 서브클래스 간에 다시 사용할 수 있습니다. 예를 들어 클래스는 Base ID 0가 있는 필드를 선언할 수 있으며 클래스는 Sub : Base ID가 같은 0다른 필드를 선언할 수 있습니다.

숫자

  • 숫자 필드의 부호 는 변경할 수 없습니다.
    • intuint 사이의 변환이 유효하지 않습니다.
  • 숫자 필드의 너비 를 변경할 수 있습니다.
    • 예를 들어, int에서 long으로, 또는 ulong에서 ushort으로의 변환이 지원됩니다.
    • 폭을 줄이는 변환은 필드의 런타임 값으로 인해 오버플로가 발생하면 예외를 발생시킵니다.
    • ulong에서 ushort로의 변환은 런타임 값이 ushort.MaxValue보다 작은 경우에만 지원됩니다.
    • double에서 float로의 변환은 런타임 값이 float.MinValue에서 float.MaxValue 사이인 경우에만 지원됩니다.
    • decimaldouble보다 범위가 더 좁은 float의 경우에도 마찬가지입니다.

복사기

Orleans 는 일부 동시성 버그 클래스의 안전을 포함하여 기본적으로 안전을 촉진합니다. 특히 기본적으로 Orleans 곡물 호출로 전달된 개체를 즉시 복사합니다. Orleans. 직렬화는 이 복사를 용이하게 합니다. 형식에 Orleans.CodeGeneration.GenerateSerializerAttribute을 적용하면, Orleans는 그 형식에 대한 복사기도 생성합니다. Orleans 는 형식 또는 로 표시된 ImmutableAttribute개별 멤버를 복사하지 않도록 방지합니다. 자세한 내용은 Orleans의 변경 불가능한 형식에 대한 직렬화를 참조하십시오.

Serialization 모범 사례

  • 특성을 사용하여 형식 별칭을 [Alias("my-type")]. 별칭이 있는 형식의 이름은 호환성을 손상하지 않고 바꿀 수 있습니다.

  • 를 일반 record로 또는 그 반대로 변경하지class. 레코드에는 일반 멤버 외에도 기본 생성자 멤버가 있기 때문에 레코드와 클래스가 동일하게 표시되지 않습니다. 따라서 두 가지는 서로 교환할 수 없습니다.

  • ❌직렬화 가능한 형식에 대한 기존 형식 계층 구조에 새 형식을 추가하지 마세요. 기존 형식에 새 Base 클래스를 추가하면 안 됩니다. 기존 형식에 새 하위 클래스를 안전하게 추가할 수 있습니다.

  • 의 사용량을 SerializableAttribute 및 해당 GenerateSerializerAttribute 선언으로 IdAttribute.

  • ✅각 형식에 대해 모든 멤버 ID를 0으로 시작합니다. 서브클래스와 해당 기본 클래스의 ID는 안전하게 겹칠 수 있습니다. 다음 예제의 두 속성 모두 ID가 같습니다 0.

    [GenerateSerializer]
    public sealed class MyBaseClass
    {
        [Id(0)]
        public int MyBaseInt { get; set; }
    }
    
    [GenerateSerializer]
    public sealed class MySubClass : MyBaseClass
    {
        [Id(0)]
        public int MyBaseInt { get; set; }
    }
    
  • ✅필요에 따라 숫자 멤버 형식을 확장하세요. sbyteshort, int, long로 확장할 수 있습니다.

    • 숫자 멤버 형식의 범위를 좁힐 수 있지만 관찰된 값을 좁은 형식으로 올바르게 나타낼 수 없는 경우 런타임 예외가 발생합니다. 예를 들어 int.MaxValue 필드로 short 나타낼 수 없으므로 필드 intshort 범위를 좁히면 이러한 값이 발생하는 경우 런타임 예외가 발생할 수 있습니다.
  • ❌숫자 형식 멤버의 부호를 변경하지 마세요. 예를 들어 멤버의 형식을 다른 형식으로 uintintintuint변경해서는 안 됩니다.

곡물 스토리지 직렬 변환기

Orleans에는 State 속성을 통해 액세스하거나 하나 이상의 IPersistentState<TState> 값을 그레인에 주입하여 사용할 수 있는 그레인을 위한 공급자 지원 지속성 모델이 포함되어 있습니다. Orleans 7.0 이전에는 각 공급자마다 serialization 구성을 위한 서로 다른 메커니즘을 사용했습니다. 7.0에서는 이제 Orleans 범용 상태 직렬화 인터페이스가 IGrainStorageSerializer각 공급자에 대한 상태 직렬화를 일관된 방식으로 사용자 지정할 수 있도록 제공합니다. 지원되는 스토리지 공급자는 공급자의 옵션 클래스에서 속성을 설정하는 IStorageProviderSerializerOptions.GrainStorageSerializer 패턴을 구현합니다. 예를 들면 다음과 같습니다.

Grain 스토리지 직렬화는 기본적으로 Newtonsoft.Json을 사용하여 상태를 직렬화합니다. 구성 시 이 속성을 수정할 수 있습니다. 다음 예제에서는 OptionsBuilder<TOptions를 사용하여 이를 보여 줍니다.>

siloBuilder.AddAzureBlobGrainStorage(
    "MyGrainStorage",
    (OptionsBuilder<AzureBlobStorageOptions> optionsBuilder) =>
    {
        optionsBuilder.Configure<IMySerializer>(
            (options, serializer) => options.GrainStorageSerializer = serializer);
    });

자세한 내용은 OptionsBuilder API를 참조하세요.

Orleans에는 확장 가능한 고급 serialization 프레임워크가 있습니다. Orleans는 그레인 요청 및 응답 메시지, 그리고 그레인의 영구 상태 객체에 전달된 데이터 형식을 직렬화합니다. 이 프레임워크 Orleans 의 일부로 이러한 데이터 형식에 대한 serialization 코드를 자동으로 생성합니다. 이미 .NET 직렬화 가능한 형식에 대해 보다 효율적인 serialization/deserialization을 생성하는 것 외에도, Orleans는 .NET 직렬화 가능하지 않은 grains 인터페이스에서 사용되는 형식에 대한 serializer를 생성하려고 합니다. 프레임워크에는 목록, 사전, 문자열, 기본 형식, 배열 등 자주 사용되는 유형에 대한 효율적인 기본 제공 직렬 변환기 세트도 포함되어 있습니다.

'serializer'의 두 가지 중요한 기능은 동적 형식/임의 다형성과 객체 동일성으로, 여러 타사 serialization 프레임워크와 차별화됩니다.

  1. 동적 형식 및 임의 다형성: Orleans 곡물 호출에 전달된 형식에 제한을 적용하지 않고 실제 데이터 형식의 동적 특성을 유지 관리합니다. 예를 들어, grain 인터페이스의 메서드가 IDictionary를 수락하도록 선언되었지만, 런타임에 발신자가 SortedDictionary<TKey,TValue>를 전달하면, 수신자는 실제로 SortedDictionary를 받게 됩니다. 이는 "정적 계약"/grain 인터페이스가 이 동작을 명시하지 않았음에도 발생하는 일입니다.

  2. 객체의 동일성 유지: 동일한 객체가 여러 번 그레인 호출의 인수로 전달되거나 인수에서 두 번 이상 간접적으로 참조되는 경우, Orleans 는 그것을 한 번만 직렬화합니다. 수신기 쪽 Orleans 에서 모든 참조를 올바르게 복원하여 동일한 개체에 대한 두 포인터가 deserialization 후에도 동일한 개체를 가리키도록 합니다. 개체 ID 유지는 다음과 같은 시나리오에서 중요합니다. Imagine grain A는 100개의 항목이 있는 사전을 그레인 B로 보내고, 사전의 10개 키는 A 쪽에서 동일한 개체 obj를 가리킵니다. 개체 ID를 유지하지 않으면 B는 obj의 10개의 서로 다른 복제본을 가리키는 10개의 키가 포함된 100개 엔터티의 사전을 받게 됩니다. 개체 ID가 유지되면 B 측의 사전은 A 쪽과 똑같이 보이며, 이 10개의 키는 단일 개체 obj를 가리킵니다.

표준 .NET 이진 serializer는 위의 두 가지 동작을 제공하므로, Orleans에서도 이 표준 및 익숙한 동작을 지원하는 것이 중요했습니다.

생성된 직렬 변환기

Orleans 에서는 다음 규칙을 사용하여 생성할 직렬 변환기를 결정합니다.

  1. 핵심 Orleans 라이브러리를 참조하는 모든 어셈블리의 모든 형식을 검사합니다.
  2. 이러한 어셈블리에서 그레인 인터페이스 메서드 서명 또는 상태 클래스 서명에서 직접 참조되는 형식 또는 SerializableAttribute로 표시된 형식에 대한 serializer를 생성합니다.
  3. 또한, 그레인 인터페이스 또는 구현 프로젝트는 KnownTypeAttribute 또는 KnownAssemblyAttribute 어셈블리 수준 특성을 추가하여 직렬화 생성을 위한 임의의 형식을 가리킬 수 있습니다. 이는 코드 생성기에 특정 형식 또는 어셈블리 내의 모든 적격 형식에 대한 serializer를 생성하도록 지시합니다. 어셈블리 수준 특성에 대한 자세한 내용은 어셈블리 수준에서 특성 적용을 참조하세요.

대체 직렬화

Orleans 는 런타임에 임의 형식의 전송을 지원합니다. 따라서 기본 제공 코드 생성기는 미리 전송될 전체 형식 집합을 확인할 수 없습니다. 또한 특정 형식은 액세스할 수 없거나 액세스할 수 없는 필드private(예: readonly)가 있기 때문에 직렬 변환기를 생성할 수 없습니다. 따라서 예기치 않았거나 미리 직렬화기를 생성할 수 없는 형식을 위한 즉시 직렬화가 필요합니다. 이러한 형식을 담당하는 직렬 변환기를 대체 직렬 변환기라고 합니다. Orleans는 두 개의 대체 직렬 변환기와 함께 제공됩니다.

FallbackSerializationProvider 속성을 사용하여 ClientConfiguration (클라이언트) 및 GlobalConfiguration (사일로) 모두에서 대체 직렬 변환기를 구성합니다.

// Client configuration
var clientConfiguration = new ClientConfiguration();
clientConfiguration.FallbackSerializationProvider =
    typeof(FantasticSerializer).GetTypeInfo();

// Global configuration
var globalConfiguration = new GlobalConfiguration();
globalConfiguration.FallbackSerializationProvider =
    typeof(FantasticSerializer).GetTypeInfo();

또는 XML 구성에서 대체 serialization 공급자를 지정합니다.

<Messaging>
    <FallbackSerializationProvider
        Type="GreatCompany.FantasticFallbackSerializer, GreatCompany.SerializerAssembly"/>
</Messaging>

BinaryFormatterSerializer는 기본 대체 직렬 변환기입니다.

경고

BinaryFormatter를 사용한 이진 직렬화는 위험할 수 있습니다. 자세한 내용은 BinaryFormatter 보안 가이드BinaryFormatter 마이그레이션 가이드를 참조하세요.

예외 직렬화

예외는 대체 직렬 변환기를 사용하여 직렬화됩니다. 기본 구성에서는 BinaryFormatter이 대체 직렬 변환기입니다. 따라서 예외 형식의 모든 속성을 올바르게 serialization하려면 ISerializable 패턴을 따라야 합니다.

다음은 올바르게 구현된 serialization을 사용하는 예외 형식의 예입니다.

[Serializable]
public class MyCustomException : Exception
{
    public string MyProperty { get; }

    public MyCustomException(string myProperty, string message)
        : base(message)
    {
        MyProperty = myProperty;
    }

    public MyCustomException(string transactionId, string message, Exception innerException)
        : base(message, innerException)
    {
        MyProperty = transactionId;
    }

    // Note: This is the constructor called by BinaryFormatter during deserialization
    public MyCustomException(SerializationInfo info, StreamingContext context)
        : base(info, context)
    {
        MyProperty = info.GetString(nameof(MyProperty));
    }

    // Note: This method is called by BinaryFormatter during serialization
    public override void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        base.GetObjectData(info, context);
        info.AddValue(nameof(MyProperty), MyProperty);
    }
}

Serialization 모범 사례

serialization은 Orleans에서 두 가지 주요 목적으로 사용됩니다.

  1. 런타임에 그레인과 클라이언트 간에 데이터를 전송하기 위한 유선 형식입니다.
  2. 나중에 검색할 수 있는 수명이 긴 데이터를 유지하기 위한 스토리지 형식입니다.

Orleans에서 생성한 직렬 변환기는 유연성, 성능 및 다양성으로 인해 첫 번째 목적에 적합합니다. 명시적으로 버전에 관대하지 않으므로 두 번째 목적에 적합하지 않습니다. 영구 데이터에 대해 프로토콜 버퍼와 같은 버전 내성 직렬 변환기를 구성하는 것이 좋습니다. 프로토콜 버퍼는 Orleans.Serialization.ProtobufSerializer NuGet 패키지의 Orleans을(를) 통해 지원됩니다. 선택한 serializer에 대한 모범 사례를 따라 버전 허용 범위를 확인합니다. 위에서 설명한 대로 구성 속성을 사용하여 SerializationProviders 타사 직렬 변환기를 구성합니다.