グレインでメソッドを呼び出す前に、まずそのグレインへの参照が必要です。 グレイン参照は、対応するグレイン クラスと同じグレイン インターフェイスを実装するプロキシ オブジェクトです。 ターゲット グレインの論理 ID (型と一意キー) をカプセル化します。 グレイン参照を使用して、ターゲット グレインを呼び出します。 各グレイン参照は 1 つのグレイン (グレイン クラスの 1 つのインスタンス) を指しますが、同じグレインへの複数の独立した参照を作成できます。
グレイン参照はターゲット グレインの論理 ID を表しているため、グレインの物理的な場所とは無関係であり、システムの再起動が完了しても有効なままです。 他の .NET オブジェクトと同様に、グレイン参照を使用できます。 メソッドに渡したり、メソッドの戻り値として使用したり、永続的ストレージに保存したりすることもできます。
グレイン参照を取得するには、グレインの ID を IGrainFactory.GetGrain<TGrainInterface>(Type, Guid) メソッドに渡します。ここで、 T
はグレイン インターフェイスであり、 key
はその型内のグレインの一意のキーです。
次の例は、前に定義した IPlayerGrain
インターフェイスのグレイン参照を取得する方法を示しています。
グレイン クラス内から:
// This would typically be read from an HTTP request parameter or elsewhere.
Guid playerId = Guid.NewGuid();
IPlayerGrain player = GrainFactory.GetGrain<IPlayerGrain>(playerId);
Orleansクライアント コードから:
// This would typically be read from an HTTP request parameter or elsewhere.
Guid playerId = Guid.NewGuid();
IPlayerGrain player = client.GetGrain<IPlayerGrain>(playerId);
グレイン参照には、次の 3 つの情報が含まれています。
- グレイン クラスを一意に識別するグレイン の種類。
- グレイン キー: グレイン クラスの論理インスタンスを一意に識別します。
- グレイン参照が実装する必要がある インターフェイス 。
注
グレインの 種類 と キー が グレイン ID を形成します。
上記の IGrainFactory.GetGrain 呼び出しでは、次の 3 つのうち 2 つだけが受け入れられたことに注意してください。
- グレイン参照によって実装される インターフェイス (
IPlayerGrain
)。 - グレインキーは、
playerId
の値です。
グレイン参照にはグレインの種類、キー、およびインターフェイスが含まれていることが示されているにもかかわらず、例ではOrleansとインターフェイスしか提供されていません。 これは、 Orleans がグレイン インターフェイスとグレイン型の間のマッピングを維持するためです。 グレイン ファクトリに IShoppingCartGrain
を要求すると、 Orleans はそのマッピングを参照して対応するグレインの種類を見つけ、参照を作成できるようにします。 これは、グレイン インターフェイスの実装が 1 つしかない場合に機能します。 ただし、複数の実装がある場合は、 GetGrain
呼び出しでそれらを明確にする必要があります。 詳細については、次のセクション「 粒度の解像度のあいまいさを解消する」を参照してください。
注
Orleans では、コンパイル時にアプリケーション内の各グレイン インターフェイスに対してグレイン参照の実装型が生成されます。 これらのグレイン参照実装は、 Orleans.Runtime.GrainReference クラスから継承されます。
GetGrain
は、要求されたグレイン インターフェイスに対応する、生成された Orleans.Runtime.GrainReference 実装のインスタンスを返します。
グレインタイプの解像度に関するあいまいさを解消する
次の例のように、グレイン インターフェイスの複数の実装が存在する場合、 Orleans はグレイン参照を作成するときに目的の実装を決定しようとします。 次の例では、 ICounterGrain
インターフェイスの実装が 2 つあります。
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
}
次の GetGrain
呼び出しでは、Orleans が ICounterGrain
をグレイン クラスのいずれかに明確にマッピングする手段がわからないため、例外がスローされます。
// This will throw an exception: there is no unambiguous mapping from ICounterGrain to a grain class.
ICounterGrain myCounter = grainFactory.GetGrain<ICounterGrain>("my-counter");
次のメッセージを含む System.ArgumentException がスローされます。
Unable to identify a single appropriate grain type for interface ICounterGrain. Candidates: upcounter (UpCounterGrain), downcounter (DownCounterGrain)
このエラー メッセージは、要求されたグレイン インターフェイスの種類 (Orleans) に一致するグレイン実装ICounterGrain
検出されたことを示します。 グレインの種類名 (upcounter
と downcounter
) とグレイン クラス (UpCounterGrain
と DownCounterGrain
) が表示されます。
注
前のエラー メッセージのグレイン型の名前 ( upcounter
と downcounter
) は、グレイン クラス名 、 UpCounterGrain
、および DownCounterGrain
からそれぞれ派生します。 これは Orleans の既定の動作であり、グレイン クラスに [GrainType(string)]
属性を追加することでカスタマイズできます。 例えば次が挙げられます。
[GrainType("up")]
public class UpCounterGrain : IUpCounterGrain { /* as above */ }
このあいまいさを解決するには、次のサブセクションで詳しく説明する方法がいくつかあります。
特別なマーカーインターフェースを使用してグレインの種類を区別する
これらのグレインを明確に区別する最も明確な方法は、一意のグレイン インターフェイスを提供することです。 たとえば、次の例のように、インターフェイス IUpCounterGrain
を UpCounterGrain
クラスに追加し、インターフェイス IDownCounterGrain
を DownCounterGrain
クラスに追加した場合、あいまいなIUpCounterGrain
型ではなく、IDownCounterGrain
またはGetGrain<T>
を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
}
いずれかのグレインへの参照を作成するには、次のコードを検討してください。
// 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");
注
前の例では、同じキーと異なるグレインの種類を持つ 2 つのグレイン参照を作成しました。 1 つ目は、 myUpCounter
変数に格納され、ID upcounter/my-counter
を持つグレインを参照します。 2 つ目は、 myDownCounter
変数に格納され、ID downcounter/my-counter
を持つグレインを参照します。 グレイン の種類 とグレイン キー の組み合わせによって、グレインが一意に識別されます。 したがって、 myUpCounter
と myDownCounter
は異なるグレインを指します。
グレイン クラス プレフィックスを指定してグレインの種類を明確にする
IGrainFactory.GetGrainにグレイン クラス名のプレフィックスを指定できます。次に例を示します。
ICounterGrain myUpCounter = grainFactory.GetGrain<ICounterGrain>("my-counter", grainClassNamePrefix: "Up");
ICounterGrain myDownCounter = grainFactory.GetGrain<ICounterGrain>("my-counter", grainClassNamePrefix: "Down");
名前付け規則を使用した既定のグレイン実装の指定
同じグレイン インターフェイスの複数の実装を明確に区別する場合、 Orleans は、インターフェイス名から先頭の 'I' を削除する規則を使用して実装を選択します。 たとえば、インターフェイス名がICounterGrain
であり、CounterGrain
とDownCounterGrain
の 2 つの実装がある場合、Orleansは、次の例のように、CounterGrain
への参照を求められたときにICounterGrain
を選択します。
/// This will refer to an instance of CounterGrain, since that matches the convention.
ICounterGrain myUpCounter = grainFactory.GetGrain<ICounterGrain>("my-counter");
属性を使用した既定のグレインの種類の指定
次の例に示すように、 Orleans.Metadata.DefaultGrainTypeAttribute 属性をグレイン インターフェイスに追加して、そのインターフェイスの既定の実装のグレインの種類を指定できます。
[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");
解決されたグレイン ID を指定してグレインの種類を明確にする
IGrainFactory.GetGrainのオーバーロードの中には、Orleans.Runtime.GrainId型の引数を受け入れるものもあります。 これらのオーバーロードを使用する場合、 Orleans インターフェイス型からグレイン型にマップする必要がないため、解決するあいまいさはありません。 例えば次が挙げられます。
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"));
.NET