Serializacja w programie Orleans
Istnieją zasadniczo dwa rodzaje serializacji używane w programie Orleans:
- Serializacja wywołań ziarna — używana do serializacji obiektów przekazywanych do i z ziarna.
- Serializacja magazynu ziarna — służy do serializacji obiektów do i z systemów magazynowania.
Większość tego artykułu jest przeznaczona do serializacji wywołań ziarna za pośrednictwem struktury serializacji zawartej w programie Orleans. W sekcji Serializatory magazynowania ziarna omówiono serializacji magazynowania ziarna.
Użyj Orleans serializacji
Orleans zawiera zaawansowaną i rozszerzalną strukturę serializacji, która może być nazywana . Orleans Serializacja. Struktura serializacji zawarta w programie Orleans została zaprojektowana w celu spełnienia następujących celów:
- Wysoka wydajność — serializator został zaprojektowany i zoptymalizowany pod kątem wydajności. Więcej szczegółów można znaleźć w tej prezentacji.
- Wysoka wierność — serializator wiernie reprezentuje większość elementów . System typów platformy NET, w tym obsługa typów ogólnych, polimorfizm, hierarchie dziedziczenia, tożsamość obiektu i cykliczne grafy. Wskaźniki nie są obsługiwane, ponieważ nie są przenośne między procesami.
- Elastyczność — serializator można dostosować do obsługi bibliotek innych firm przez utworzenie zastępców lub delegowanie do zewnętrznych bibliotek serializacji, takich jak System.Text.Json, Newtonsoft.Json i Google.Protobuf.
- Tolerancja wersji — serializator umożliwia rozwijanie typów aplikacji wraz z upływem czasu i obsługę:
- Dodawanie i usuwanie członków
- Podklasowanie
- Rozszerzanie i zawężanie liczbowe (np
int
. do/zlong
,float
do/zdouble
) - Zmienianie nazw typów
Reprezentacja typów o wysokiej wierności jest dość rzadka dla serializatorów, więc niektóre punkty uzasadniają dalsze opracowanie:
Typy dynamiczne i dowolny polimorfizm: Orleans nie wymusza ograniczeń typów, które mogą być przekazywane w wywołaniach ziarna i utrzymują dynamiczny charakter rzeczywistego typu danych. Oznacza to na przykład, że jeśli metoda w interfejsach ziarna jest zadeklarowana do akceptowania IDictionary , ale w czasie wykonywania, nadawca SortedDictionary<TKey,TValue>przekazuje , odbiorca rzeczywiście otrzyma
SortedDictionary
(chociaż interfejs "kontrakt statyczny"/ziarno nie określił tego zachowania).Utrzymywanie tożsamości obiektu: jeśli ten sam obiekt jest przekazywany wiele typów w argumentach wywołania ziarna lub jest pośrednio wskazywany więcej niż raz z argumentów, Orleans serializuje go tylko raz. Po stronie odbiorcy wszystkie odwołania zostaną poprawnie przywrócone, Orleans tak aby dwa wskaźniki do tego samego obiektu nadal wskazywały ten sam obiekt po deserializacji. Tożsamość obiektu jest ważna do zachowania w scenariuszach, takich jak poniżej. Imagine grain A wysyła słownik z 100 wpisów do ziarna B, a 10 kluczy w słowniku wskazuje ten sam obiekt,
obj
, po stronie A. Bez zachowania tożsamości obiektu B otrzyma słownik zawierający 100 wpisów z tymi 10 kluczami wskazującymi na 10 różnych klonówobj
obiektu . W przypadku zachowania tożsamości obiektu słownik po stronie B wygląda dokładnie tak samo jak po stronie A z tymi 10 kluczami wskazującymi pojedynczy obiektobj
. Należy pamiętać, że ponieważ domyślne implementacje kodu skrótu ciągu na platformie .NET są losowe dla poszczególnych procesów, kolejność wartości w słownikach i zestawach skrótów (na przykład) może nie być zachowywana.
Aby zapewnić tolerancję wersji, serializator wymaga, aby deweloperzy mogli jawnie określać, które typy i składowe są serializowane. Staraliśmy się to jak najbardziej bezboleśnie. Aby poinstruować Orleans generowanie kodu serializatora dla danego typu, należy oznaczyć wszystkie typy Orleans.GenerateSerializerAttribute możliwe do serializacji. Po wykonaniu tej czynności możesz użyć dołączonej poprawki kodu, aby dodać wymagane Orleans.IdAttribute do serializacji elementów członkowskich w typach, jak pokazano tutaj:
Oto przykład typu z możliwością serializacji w Orleanspliku , pokazujący sposób stosowania atrybutów.
[GenerateSerializer]
public class Employee
{
[Id(0)]
public string Name { get; set; }
}
Orleans obsługuje dziedziczenie i serializuje poszczególne warstwy w hierarchii oddzielnie, co umożliwia im posiadanie unikatowych identyfikatorów składowych.
[GenerateSerializer]
public class Publication
{
[Id(0)]
public string Title { get; set; }
}
[GenerateSerializer]
public class Book : Publication
{
[Id(0)]
public string ISBN { get; set; }
}
W poprzednim kodzie należy pamiętać, że zarówno Publication
elementy członkowskie, jak i Book
z elementami [Id(0)]
, mimo że Book
pochodzą z Publication
elementu . Jest to zalecana praktyka, Orleans ponieważ identyfikatory elementów członkowskich są ograniczone do poziomu dziedziczenia, a nie całego typu. Składowe można dodawać i usuwać z Publication
i Book
niezależnie, ale nie można wstawić nowej klasy bazowej do hierarchii po wdrożeniu aplikacji bez specjalnej uwagi.
Orleans Obsługuje również serializacji typów z elementami internal
, private
i readonly
, takimi jak w tym przykładzie:
[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}";
}
Domyślnie serializuje typ, Orleans kodując jego pełną nazwę. Możesz to zastąpić, dodając element Orleans.AliasAttribute. Spowoduje to serializacji typu przy użyciu nazwy odpornej na zmianę nazwy bazowej klasy lub przeniesienie jej między zestawami. Aliasy typów są globalnie ograniczone i nie można mieć dwóch aliasów o tej samej wartości w aplikacji. W przypadku typów ogólnych wartość aliasu musi zawierać liczbę parametrów ogólnych poprzedzonych na przykład backtick, MyGenericType<T, U>
może mieć alias [Alias("mytype`2")]
.
Serializacji record
typów
Składowe zdefiniowane w konstruktorze podstawowym rekordu mają domyślnie niejawne identyfikatory. Innymi słowy, Orleans obsługuje serializacji record
typów. Oznacza to, że nie można zmienić kolejności parametrów dla już wdrożonego typu, ponieważ przerywa to zgodność z poprzednimi wersjami aplikacji (w przypadku uaktualnienia stopniowego) i z serializowanymi wystąpieniami tego typu w magazynie i strumieniach. Elementy członkowskie zdefiniowane w treści typu rekordu nie współużytkują tożsamości z podstawowymi parametrami konstruktora.
[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; }
}
Jeśli nie chcesz, aby podstawowe parametry konstruktora były automatycznie dołączane jako pola możliwe do serializacji, możesz użyć polecenia [GenerateSerializer(IncludePrimaryConstructorParameters = false)]
.
Zastępcze do serializacji typów obcych
Czasami może być konieczne przekazanie typów między ziarnami, nad którymi nie masz pełnej kontroli. W takich przypadkach konwersja na i z określonego typu niestandardowego w kodzie aplikacji może być niepraktyczna. Orleans oferuje rozwiązanie tych sytuacji w postaci typów zastępczych. Zastępcze są serializowane zamiast ich typu docelowego i mają funkcje konwersji na i z typu docelowego. Rozważmy następujący przykład typu obcego i odpowiadającego mu zastępczego i konwertera:
// 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
};
}
Powyższy kod:
- Jest
MyForeignLibraryValueType
to typ spoza kontrolki zdefiniowany w bibliotece zużywanej. - Jest
MyForeignLibraryValueTypeSurrogate
typem zastępczym, który mapuje naMyForeignLibraryValueType
. - Określa RegisterConverterAttribute , że
MyForeignLibraryValueTypeSurrogateConverter
działa jako konwerter do mapowania na i z dwóch typów. Klasa jest implementacją interfejsu IConverter<TValue,TSurrogate> .
Orleans obsługuje serializacji typów w hierarchiach typów (typy pochodzące z innych typów). W przypadku, gdy typ obcy może pojawić się w hierarchii typów (na przykład jako klasa bazowa dla jednego z własnych typów), należy dodatkowo zaimplementować Orleans.IPopulator<TValue,TSurrogate> interfejs. Rozważmy następujący przykład:
// 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; }
}
Reguły przechowywania wersji
Tolerancja wersji jest obsługiwana, jeśli deweloper stosuje zestaw reguł podczas modyfikowania typów. Jeśli deweloper zna systemy, takie jak protokołu Google (Protobuf), te reguły będą znane.
Typy złożone (class
& struct
)
- Dziedziczenie jest obsługiwane, ale modyfikowanie hierarchii dziedziczenia obiektu nie jest obsługiwane. Nie można dodać klasy bazowej klasy, zmienić jej na inną lub usunąć.
- Z wyjątkiem niektórych typów liczbowych, opisanych w poniższej sekcji Numeryczne , nie można zmienić typów pól.
- Pola można dodawać lub usuwać w dowolnym momencie w hierarchii dziedziczenia.
- Nie można zmienić identyfikatorów pól.
- Identyfikatory pól muszą być unikatowe dla każdego poziomu w hierarchii typów, ale mogą być używane ponownie między klasami bazowymi i podkatałami. Na przykład
Base
klasa może zadeklarować pole o identyfikatorze0
, a inne pole może być zadeklarowane za pomocąSub : Base
tego samego identyfikatora.0
Wartości numeryczne
- Nie można zmienić podpisu pola liczbowego.
- Konwersje między elementami
int
iuint
są nieprawidłowe.
- Konwersje między elementami
- Szerokość pola liczbowego można zmienić.
- Na przykład: obsługiwane są konwersje z
int
dolong
lubulong
doushort
. - Konwersje, które zawężają szerokość, będą zgłaszane, jeśli wartość środowiska uruchomieniowego pola spowoduje przepełnienie.
- Konwersja z
ulong
naushort
jest obsługiwana tylko wtedy, gdy wartość w czasie wykonywania jest mniejsza niżushort.MaxValue
. - Konwersje z
double
dofloat
są obsługiwane tylko wtedy, gdy wartość środowiska uruchomieniowego mieści się międzyfloat.MinValue
ifloat.MaxValue
. - Podobnie w przypadku elementu
decimal
, który ma węższy zakres niż idouble
float
.
- Konwersja z
- Na przykład: obsługiwane są konwersje z
Kopiarki
Orleans domyślnie promuje bezpieczeństwo. Obejmuje to bezpieczeństwo niektórych klas błędów współbieżności. W szczególności Orleans natychmiast skopiuje obiekty przekazywane w wywołaniach ziarna domyślnie. To kopiowanie jest obsługiwane przez program Orleans. Serializacja i zastosowanie Orleans.CodeGeneration.GenerateSerializerAttribute do typu Orleans spowoduje również wygenerowanie kopii dla tego typu. Orleans Pozwoli uniknąć kopiowania typów lub pojedynczych elementów członkowskich oznaczonych przy użyciu elementu ImmutableAttribute. Aby uzyskać więcej informacji, zobacz Serializacja niezmiennych typów w programie Orleans.
Najlepsze rozwiązania dotyczące serializacji
✅Podaj aliasy typów przy użyciu atrybutu
[Alias("my-type")]
. Nazwy typów z aliasami można zmienić bez niezgodności.❌Nie zmieniaj
record
obiektu na zwykłyclass
lub odwrotnie. Rekordy i klasy nie są reprezentowane w identyczny sposób, ponieważ rekordy mają podstawowe elementy członkowskie konstruktora oprócz zwykłych składowych i dlatego te dwa nie są wymienne.❌Nie dodawaj nowych typów do istniejącej hierarchii typów dla typu możliwego do serializacji. Nie można dodać nowej klasy bazowej do istniejącego typu. Możesz bezpiecznie dodać nową podklasę do istniejącego typu.
✅Zastąp wartości użycia SerializableAttribute elementem i GenerateSerializerAttribute odpowiednimi IdAttribute deklaracjami.
✅Uruchom wszystkie identyfikatory składowych o wartości zero dla każdego typu. Identyfikatory w podklasie i jej klasie bazowej mogą bezpiecznie nakładać się na siebie. Obie właściwości w poniższym przykładzie mają identyfikatory równe
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; } }
✅W razie potrzeby należy poszerzyć typy składowych liczbowych. Możesz poszerz
sbyte
doshort
.long
int
- Można zawęzić typy składowych liczbowych, ale spowoduje wyjątek środowiska uruchomieniowego, jeśli obserwowane wartości nie mogą być poprawnie reprezentowane przez zawężonego typu. Na przykład
int.MaxValue
nie może być reprezentowana przezshort
pole, więc zawężenieint
pola w celushort
może spowodować wyjątek środowiska uruchomieniowego, jeśli taka wartość została napotkana.
- Można zawęzić typy składowych liczbowych, ale spowoduje wyjątek środowiska uruchomieniowego, jeśli obserwowane wartości nie mogą być poprawnie reprezentowane przez zawężonego typu. Na przykład
❌Nie zmieniaj podpisu elementu członkowskiego typu liczbowego. Na przykład nie można zmienić typu elementu członkowskiego z
uint
naint
lub naint
uint
wartość , na przykład.
Serializatory magazynu ziarna
Orleans Zawiera model trwałości opartej na dostawcy dla ziarna, do którego uzyskuje dostęp za pośrednictwem State właściwości lub przez wstrzyknięcie jednej lub większej liczby IPersistentState<TState> wartości do ziarna. Przed Orleans 7.0 każdy dostawca miał inny mechanizm konfigurowania serializacji. W Orleans wersji 7.0 istnieje teraz interfejs serializatora stanu ziarna ogólnego przeznaczenia, IGrainStorageSerializerktóry oferuje spójny sposób dostosowywania serializacji stanu dla każdego dostawcy. Obsługiwani dostawcy magazynu implementują wzorzec, który obejmuje ustawienie IStorageProviderSerializerOptions.GrainStorageSerializer właściwości w klasie opcji dostawcy, na przykład:
- DynamoDBStorageOptions.GrainStorageSerializer
- AzureBlobStorageOptions.GrainStorageSerializer
- AzureTableStorageOptions.GrainStorageSerializer
- GrainStorageSerializer
Serializacja magazynu ziarna jest obecnie domyślnie ustawiona na Newtonsoft.Json
serializacji stanu. Tę właściwość można zastąpić, modyfikując tę właściwość w czasie konfiguracji. W poniższym przykładzie pokazano to przy użyciu polecenia OptionsBuilder<TOptions>:
siloBuilder.AddAzureBlobGrainStorage(
"MyGrainStorage",
(OptionsBuilder<AzureBlobStorageOptions> optionsBuilder) =>
{
optionsBuilder.Configure<IMySerializer>(
(options, serializer) => options.GrainStorageSerializer = serializer);
});
Aby uzyskać więcej informacji, zobacz OptionsBuilder API (Interfejs API programu OptionsBuilder).
Orleans ma zaawansowaną i rozszerzalną strukturę serializacji. Orleans serializuje typy danych przekazywane w komunikatach żądania ziarna i odpowiedzi, a także obiekty stanu trwałego ziarna. W ramach tej struktury Orleans automatycznie generuje kod serializacji dla tych typów danych. Oprócz generowania bardziej wydajnej serializacji/deserializacji typów, które są już . Z możliwością Orleans serializacji net próbuje również wygenerować serializatory dla typów używanych w interfejsach ziarna, które nie są . Z możliwością serializacji net. Struktura zawiera również zestaw wydajnych wbudowanych serializatorów dla często używanych typów: list, słowników, ciągów, elementów pierwotnych, tablic itp.
Dwie ważne cechy Orleansserializatora odróżniają ją od wielu innych struktur serializacji innych firm: dynamiczne typy/dowolną polimorfizm i tożsamość obiektów.
Typy dynamiczne i dowolny polimorfizm: Orleans nie wymusza ograniczeń typów, które mogą być przekazywane w wywołaniach ziarna i utrzymują dynamiczny charakter rzeczywistego typu danych. Oznacza to na przykład, że jeśli metoda w interfejsach ziarna jest zadeklarowana do akceptowania IDictionary , ale w czasie wykonywania, nadawca SortedDictionary<TKey,TValue>przekazuje , odbiorca rzeczywiście otrzyma
SortedDictionary
(chociaż interfejs "kontrakt statyczny"/ziarno nie określił tego zachowania).Utrzymywanie tożsamości obiektu: jeśli ten sam obiekt jest przekazywany wiele typów w argumentach wywołania ziarna lub jest pośrednio wskazywany więcej niż raz z argumentów, Orleans serializuje go tylko raz. Po stronie odbiorcy wszystkie odwołania zostaną poprawnie przywrócone, Orleans tak aby dwa wskaźniki do tego samego obiektu nadal wskazywały ten sam obiekt po deserializacji. Tożsamość obiektu jest ważna do zachowania w scenariuszach, takich jak poniżej. Imagine grain A wysyła słownik z 100 wpisów do ziarna B, a 10 kluczy w słowniku wskazuje ten sam obiekt, obj, po stronie A. Bez zachowania tożsamości obiektu B otrzyma słownik zawierający 100 wpisów z tymi 10 kluczami wskazującymi 10 różnych klonów obj. W przypadku zachowania tożsamości obiektu słownik po stronie B wygląda dokładnie tak samo jak po stronie A z tymi 10 kluczami wskazującymi pojedynczy obiekt obj.
Powyższe dwa zachowania są udostępniane przez standardowy serializator binarny platformy .NET i dlatego ważne było, abyśmy również obsługiwali ten standard i znane zachowanie Orleans .
Wygenerowane serializatory
Orleans Używa następujących reguł, aby zdecydować, które serializatory mają być generowane. Reguły to:
- Skanuj wszystkie typy we wszystkich zestawach, które odwołują się do biblioteki podstawowej Orleans .
- Z tych zestawów: generuj serializatory dla typów, do których bezpośrednio odwołuje się sygnatury metody ziarna lub sygnatury klasy stanu lub dla dowolnego typu oznaczonego znakiem SerializableAttribute.
- Ponadto interfejs ziarna lub projekt implementacji może wskazywać na dowolne typy generowania serializacji, dodając KnownTypeAttribute atrybuty lub na poziomie zestawu, aby poinformować generator kodu o generowaniu serializatorów dla określonych typów lub KnownAssemblyAttribute wszystkich kwalifikujących się typów w zestawie. Aby uzyskać więcej informacji na temat atrybutów na poziomie zestawu, zobacz Stosowanie atrybutów na poziomie zestawu.
Serializacja rezerwowa
Orleans obsługuje przesyłanie dowolnych typów w czasie wykonywania, dlatego wbudowany generator kodu nie może określić całego zestawu typów, które będą przesyłane z wyprzedzeniem. Ponadto niektóre typy nie mogą mieć wygenerowanych serializatorów, ponieważ są niedostępne (na przykład ) lub mają niedostępne pola (na przykład private
readonly
). W związku z tym istnieje potrzeba serializacji typu just in time, które były nieoczekiwane lub nie mogły być generowane serializatory z wyprzedzeniem. Serializator odpowiedzialny za te typy jest nazywany serializatorem rezerwowym. Orleans dostarczanych z dwoma serializatorami rezerwowymi:
- Orleans.Serialization.BinaryFormatterSerializer, który używa elementu . Net's BinaryFormatter; i
- Orleans.Serialization.ILBasedSerializer, który emituje instrukcje CIL w czasie wykonywania w celu utworzenia serializatorów korzystających Orleansze struktury serializacji w celu serializacji każdego pola. Oznacza to, że jeśli typ
MyPrivateType
niedostępny zawiera poleMyType
, które ma niestandardowy serializator, niestandardowy serializator będzie używany do serializacji.
Serializator rezerwowy można skonfigurować przy użyciu FallbackSerializationProvider właściwości zarówno ClientConfiguration na kliencie, jak i GlobalConfiguration na silosach.
// Client configuration
var clientConfiguration = new ClientConfiguration();
clientConfiguration.FallbackSerializationProvider =
typeof(FantasticSerializer).GetTypeInfo();
// Global configuration
var globalConfiguration = new GlobalConfiguration();
globalConfiguration.FallbackSerializationProvider =
typeof(FantasticSerializer).GetTypeInfo();
Alternatywnie można określić rezerwowego dostawcę serializacji w konfiguracji XML:
<Messaging>
<FallbackSerializationProvider
Type="GreatCompany.FantasticFallbackSerializer, GreatCompany.SerializerAssembly"/>
</Messaging>
Jest BinaryFormatterSerializer to domyślny serializator rezerwowy.
Ostrzeżenie
Serializacja binarna z BinaryFormatter
programem może być niebezpieczna. Aby uzyskać więcej informacji, zobacz Przewodnik po zabezpieczeniach BinaryFormatter i Przewodnik migracji BinaryFormatter.
Serializacja wyjątków
Wyjątki są serializowane przy użyciu serializatora rezerwowego. Przy użyciu konfiguracji domyślnej jest serializator rezerwowy i BinaryFormatter
dlatego należy przestrzegać wzorca ISerializable, aby zapewnić poprawną serializacji wszystkich właściwości w typie wyjątku.
Oto przykład typu wyjątku z poprawnie zaimplementowaną serializacji:
[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);
}
}
Najlepsze rozwiązania dotyczące serializacji
Serializacja służy dwóm podstawowym celom w programie Orleans:
- Jako format przewodu do przesyłania danych między ziarnami i klientami w czasie wykonywania.
- Jako format magazynu do utrwalania długotrwałych danych na potrzeby późniejszego pobierania.
Serializatory generowane przez Orleans program są odpowiednie do pierwszego celu ze względu na ich elastyczność, wydajność i wszechstronność. Nie są one tak odpowiednie do drugiego celu, ponieważ nie są jawnie odporne na wersje. Zaleca się, aby użytkownicy konfigurowali serializator odporny na wersje, taki jak protokołu dla danych trwałych. protokołu są obsługiwane za pośrednictwem Orleans.Serialization.ProtobufSerializer
programu Microsoft.Orleans. OrleansGoogleUtils pakiet NuGet. Najlepsze rozwiązania dotyczące wybranego serializatora powinny być stosowane w celu zapewnienia tolerancji wersji. Serializatory innych firm można skonfigurować przy użyciu właściwości konfiguracji zgodnie z SerializationProviders
powyższym opisem.