Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Przed wywołaniem metody na ziarnie należy najpierw odwołać się do tego ziarna. Odwołanie do ziarna jest obiektem proxy implementującym ten sam interfejs ziarna co odpowiadająca mu klasa ziarna. Hermetyzuje tożsamość logiczną (typ i unikatowy klucz) ziarna docelowego. Odwołania ziarna służą do wywoływaniów ziarna docelowego. Każde odwołanie ziarna wskazuje jedno ziarno (pojedyncze wystąpienie klasy ziarna), ale można utworzyć wiele niezależnych odwołań do tego samego ziarna.
Ponieważ referencja ziarna odnosi się do logicznej tożsamości ziarna docelowego, jest niezależna od jego fizycznej lokalizacji i pozostaje ważna nawet po całkowitym ponownym uruchomieniu systemu. Można używać odnośników ziarna jak dowolnego innego obiektu .NET. Możesz przekazać go do metody, użyć jej jako wartości zwracanej przez metodę, a nawet zapisać ją w magazynie trwałym.
Referencję do ziarna można uzyskać, przekazując tożsamość ziarna do IGrainFactory.GetGrain<TGrainInterface>(Type, Guid) metody, gdzie T jest interfejsem ziarna i key jest unikatowym kluczem ziarna w ramach swojego typu.
W poniższych przykładach pokazano, jak uzyskać odwołanie do ziarna dla interfejsu IPlayerGrain zdefiniowanego wcześniej.
Z perspektywy klasy ziarna:
// This would typically be read from an HTTP request parameter or elsewhere.
Guid playerId = Guid.NewGuid();
IPlayerGrain player = GrainFactory.GetGrain<IPlayerGrain>(playerId);
W kodzie klienta Orleans:
// This would typically be read from an HTTP request parameter or elsewhere.
Guid playerId = Guid.NewGuid();
IPlayerGrain player = client.GetGrain<IPlayerGrain>(playerId);
Odwołania do ziarna zawierają trzy informacje:
- Typ ziarna, który jednoznacznie identyfikuje klasę ziarna.
- Klucz ziarna, który jednoznacznie identyfikuje logiczne wystąpienie tej klasy ziarna.
- Interfejs, który musi być zaimplementowany przez odwołanie do ziarna.
Uwaga / Notatka
Typ ziarna i klucz tworzą tożsamość ziarna.
Zwróć uwagę, że poprzednie wywołania IGrainFactory.GetGrain akceptowały tylko dwa z tych trzech elementów:
-
Interfejs zaimplementowany przez referencję ziarna,
IPlayerGrain. -
Klucz ziarna, który jest wartością
playerId.
Pomimo stwierdzenia, że odwołanie do ziarna zawiera typ ziarna, klucz i interfejs, przykłady zawierają tylko Orleans i interfejs. Dzieje się tak, ponieważ Orleans utrzymuje mapowanie między interfejsami ziarna i typami ziarna. Gdy poprosisz fabrykę ziarna o IShoppingCartGrain, Orleans skonsultuje się z mapowaniem, aby znaleźć odpowiedni typ ziarna, aby można było utworzyć odwołanie. To działa, gdy istnieje tylko jedna implementacja interfejsu ziarna. Jeśli jednak istnieje wiele implementacji, należy je uściślić w wywołaniu GetGrain . Aby uzyskać więcej informacji, zobacz następną sekcję Uszczegółowienie rozpoznawania typów ziarna.
Uwaga / Notatka
Orleans generuje typy implementacji odniesienia ziarna dla każdego interfejsu ziarna w aplikacji podczas kompilacji. Te implementacje referencyjne ziaren dziedziczą z klasy Orleans.Runtime.GrainReference.
GetGrain zwraca wystąpienia wygenerowanej Orleans.Runtime.GrainReference implementacji odpowiadające żądanemu interfejsowi ziarna.
Doprecyzowanie rozdzielczości typu ziarna
Jeśli istnieje wiele implementacji interfejsu ziarna, jak w poniższym przykładzie, Orleans próbuje ustalić zamierzoną implementację podczas tworzenia referencji ziarna. Rozważmy następujący przykład, w którym istnieją dwie implementacje interfejsu ICounterGrain :
public interface ICounterGrain : IGrainWithStringKey
{
ValueTask<int> UpdateCount();
}
public class UpCounterGrain : ICounterGrain
{
private int _count;
public ValueTask<string> UpdateCount() => new(++_count); // Increment count
}
public class DownCounterGrain : ICounterGrain
{
private int _count;
public ValueTask<string> UpdateCount() => new(--_count); // Decrement count
}
Poniższe wywołanie GetGrain zgłasza wyjątek, ponieważ Orleans nie wie, jak jednoznacznie mapować ICounterGrain na jedną z klas ziarna.
// This will throw an exception: there is no unambiguous mapping from ICounterGrain to a grain class.
ICounterGrain myCounter = grainFactory.GetGrain<ICounterGrain>("my-counter");
Element System.ArgumentException jest zgłaszany z następującym komunikatem:
Unable to identify a single appropriate grain type for interface ICounterGrain. Candidates: upcounter (UpCounterGrain), downcounter (DownCounterGrain)
Komunikat o błędzie informuje, które implementacje ziarna Orleans zostały odnalezione jako zgodne z żądanym typem interfejsu ziarna ICounterGrain. Przedstawia nazwy typów ziarna (upcounter i ) oraz downcounterklasy ziarna (UpCounterGrain i DownCounterGrain).
Uwaga / Notatka
Nazwy typów ziarna w poprzednim komunikacie o błędzie, upcounter i downcounter, pochodzą odpowiednio z nazw klas ziarna, UpCounterGrain i DownCounterGrain. Jest to domyślne zachowanie w Orleans programie i można go dostosować przez dodanie [GrainType(string)] atrybutu do klasy ziarna. Przykład:
[GrainType("up")]
public class UpCounterGrain : IUpCounterGrain { /* as above */ }
Istnieje kilka sposobów rozwiązania tej niejednoznaczności, szczegółowo opisanych w poniższych podsekcjach.
Rozróżnianie rodzajów ziarna za pomocą unikalnych interfejsów znaczników
Najlepszym sposobem na rozróżnienie tych ziaren jest nadanie im unikatowych interfejsów ziaren. Na przykład, jeśli dodasz interfejs IUpCounterGrain do klasy UpCounterGrain i dodasz interfejs IDownCounterGrain do klasy DownCounterGrain, jak w poniższym przykładzie, możesz rozwiązać poprawne odwołanie do ziarna, przekazując IUpCounterGrain lub IDownCounterGrain do wywołania GetGrain<T> zamiast niejednoznacznego typu ICounterGrain.
public interface ICounterGrain : IGrainWithStringKey
{
ValueTask<int> UpdateCount();
}
// Define unique interfaces for our implementations
public interface IUpCounterGrain : ICounterGrain, IGrainWithStringKey {}
public interface IDownCounterGrain : ICounterGrain, IGrainWithStringKey {}
public class UpCounterGrain : IUpCounterGrain
{
private int _count;
public ValueTask<string> UpdateCount() => new(++_count); // Increment count
}
public class DownCounterGrain : IDownCounterGrain
{
private int _count;
public ValueTask<string> UpdateCount() => new(--_count); // Decrement count
}
Aby utworzyć odwołanie do dowolnego ziarna, rozważ następujący kod:
// Get a reference to an UpCounterGrain.
ICounterGrain myUpCounter = grainFactory.GetGrain<IUpCounterGrain>("my-counter");
// Get a reference to a DownCounterGrain.
ICounterGrain myDownCounter = grainFactory.GetGrain<IDownCounterGrain>("my-counter");
Uwaga / Notatka
W poprzednim przykładzie utworzyłeś dwa odwołania do ziaren z tym samym kluczem, ale różnych typów ziaren. Pierwszy, przechowywany w zmiennej myUpCounter , odwołuje się do ziarna o identyfikatorze upcounter/my-counter. Drugi, przechowywany w zmiennej myDownCounter , odwołuje się do ziarna o identyfikatorze downcounter/my-counter. Kombinacja typu ziarna i klucza ziarna jednoznacznie identyfikuje ziarno. W związku z tym, myUpCounter i myDownCounter odnoszą się do różnych ziaren.
Uściślanie typów ziarna przez podanie prefiksu klasy ziarna
Możesz podać prefiks nazwy klasy ziarna na IGrainFactory.GetGrain, na przykład:
ICounterGrain myUpCounter = grainFactory.GetGrain<ICounterGrain>("my-counter", grainClassNamePrefix: "Up");
ICounterGrain myDownCounter = grainFactory.GetGrain<ICounterGrain>("my-counter", grainClassNamePrefix: "Down");
Określanie domyślnej implementacji ziarna przy użyciu konwencji nazewnictwa
Podczas rozróżniania wielu implementacji tego samego interfejsu ziarna, Orleans wybiera implementację przy użyciu konwencji usuwania wiodącego "I" z nazwy interfejsu. Jeśli na przykład nazwa interfejsu to ICounterGrain i istnieją dwie implementacje, CounterGrain i DownCounterGrain, Orleans wybiera CounterGrain, gdy poprosi się o odwołanie do ICounterGrain, jak w poniższym przykładzie:
/// This will refer to an instance of CounterGrain, since that matches the convention.
ICounterGrain myUpCounter = grainFactory.GetGrain<ICounterGrain>("my-counter");
Określanie domyślnego typu ziarna przy użyciu atrybutu
Można dodać atrybut Orleans.Metadata.DefaultGrainTypeAttribute do interfejsu ziarna, aby określić typ ziarna domyślnej implementacji dla tego interfejsu, jak pokazano w poniższym przykładzie:
[DefaultGrainType("up-counter")]
public interface ICounterGrain : IGrainWithStringKey
{
ValueTask<int> UpdateCount();
}
[GrainType("up-counter")]
public class UpCounterGrain : ICounterGrain
{
private int _count;
public ValueTask<string> UpdateCount() => new(++_count); // Increment count
}
[GrainType("down-counter")]
public class DownCounterGrain : ICounterGrain
{
private int _count;
public ValueTask<string> UpdateCount() => new(--_count); // Decrement count
}
/// This will refer to an instance of UpCounterGrain, due to the [DefaultGrainType("up-counter"')] attribute
ICounterGrain myUpCounter = grainFactory.GetGrain<ICounterGrain>("my-counter");
Uściślanie typów ziarna poprzez podanie rozwiązania identyfikatora ziarna
Niektóre przeciążenia IGrainFactory.GetGrain akceptują argument typu Orleans.Runtime.GrainId. W przypadku używania tych przeciążeń Orleans nie trzeba mapować typu interfejsu na typ ziarna, więc nie ma wątpliwości co do rozwiązania. Przykład:
public interface ICounterGrain : IGrainWithStringKey
{
ValueTask<int> UpdateCount();
}
[GrainType("up-counter")]
public class UpCounterGrain : ICounterGrain
{
private int _count;
public ValueTask<string> UpdateCount() => new(++_count); // Increment count
}
[GrainType("down-counter")]
public class DownCounterGrain : ICounterGrain
{
private int _count;
public ValueTask<string> UpdateCount() => new(--_count); // Decrement count
}
// This will refer to an instance of UpCounterGrain, since "up-counter" was specified as the grain type
// and the UpCounterGrain uses [GrainType("up-counter")] to specify its grain type.
ICounterGrain myUpCounter = grainFactory.GetGrain<ICounterGrain>(GrainId.Create("up-counter", "my-counter"));