Dela via


Kornreferenser

Innan du anropar en metod för korn behöver du först en referens till det kornet. En kornreferens är ett proxyobjekt som implementerar samma korngränssnitt som motsvarande kornklass. Den kapslar in målkornets logiska identitet (typ och unik nyckel). Kornreferenser används för att göra anrop till målintervallet. Varje kornreferens är till ett enda korn (en enskild instans av kornklassen), men man kan skapa flera oberoende referenser till samma korn.

Eftersom en kornreferens representerar målkornets logiska identitet är den oberoende av kornets fysiska plats och förblir giltig även efter en fullständig omstart av systemet. Utvecklare kan använda kornreferenser som andra .NET-objekt. Den kan skickas till en metod, användas som ett metodreturvärde och till och med sparas i beständig lagring.

En kornreferens kan hämtas genom att skicka identiteten för ett korn till IGrainFactory.GetGrain<TGrainInterface>(Type, Guid) metoden, där T är korngränssnittet och key är den unika nyckeln för kornet inom typen.

Följande är exempel på hur du hämtar en kornreferens för gränssnittet IPlayerGrain som definierats ovan.

Inifrån en kornklass:

// This would typically be read from an HTTP request parameter or elsewhere.
Guid playerId = Guid.NewGuid();
IPlayerGrain player = GrainFactory.GetGrain<IPlayerGrain>(playerId);

Från Orleans klientkod:

// This would typically be read from an HTTP request parameter or elsewhere.
Guid playerId = Guid.NewGuid();
IPlayerGrain player = client.GetGrain<IPlayerGrain>(playerId);

Kornreferenser innehåller tre informationsdelar:

  1. Korntypen, som unikt identifierar kornklassen.
  2. Kornnyckeln, som unikt identifierar en logisk instans av den korniga klassen.
  3. Gränssnittet som kornreferensen måste implementera.

Kommentar

Korntypen och nyckeln utgör kornidentiteten.

Observera att ovanstående anrop till IGrainFactory.GetGrain endast accepterade två av dessa tre saker:

  • Gränssnittet som implementeras av kornreferensen, IPlayerGrain.
  • Kornnyckeln, som är värdet för playerId.

Trots att det anges att en kornreferens innehåller en korntyp, nyckel och gränssnitt, tillhandahålls Orleans exemplen endast med nyckeln och gränssnittet. Det beror på att Orleans underhåller en mappning mellan korngränssnitt och korntyper. När du ber kornfabriken om läser Orleans du dess mappning för IShoppingCartGrainatt hitta motsvarande korntyp så att den kan skapa referensen. Detta fungerar när det bara finns en implementering av ett korngränssnitt, men om det finns flera implementeringar måste du skilja dem åt i anropet GetGrain . Mer information finns i nästa avsnitt, där du kan skilja på korntypsmatchning.

Kommentar

Orleans genererar implementeringstyper för kornreferenser för varje korngränssnitt i ditt program under kompileringen. Dessa referensimplementeringar för korn ärver från Orleans.Runtime.GrainReference klassen. GetGrain returnerar instanser av den genererade Orleans.Runtime.GrainReference implementeringen som motsvarar det begärda korngränssnittet.

Tvetydig upplösning av korntyp

När det finns flera implementeringar av ett kornigt gränssnitt, till exempel i följande exempel, Orleans försöker fastställa den avsedda implementeringen när du skapar en kornreferens. Tänk på följande exempel, där det finns två implementeringar av ICounterGrain gränssnittet:

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
}

Följande anrop till GetGrain utlöser ett undantag eftersom Orleans du inte vet hur du entydigt ska mappa ICounterGrain till någon av kornklasserna.

// This will throw an exception: there is no unambiguous mapping from ICounterGrain to a grain class.
ICounterGrain myCounter = grainFactory.GetGrain<ICounterGrain>("my-counter");

Ett System.ArgumentException utlöses med följande meddelande:

Unable to identify a single appropriate grain type for interface ICounterGrain. Candidates: upcounter (UpCounterGrain), downcounter (DownCounterGrain)

Felmeddelandet anger vilken kornimplementering som matchar den begärda korngränssnittstypen Orleans . ICounterGrain Den visar korntypsnamnen (upcounter och downcounter) samt kornklasserna (UpCounterGrain och DownCounterGrain).

Kommentar

Korntypsnamnen i föregående felmeddelande, upcounter och downcounter, härleds från kornklassnamnen UpCounterGrain respektive DownCounterGrain . Det här är standardbeteendet i Orleans och det kan anpassas genom att lägga till ett [GrainType(string)] attribut i kornklassen. Till exempel:

[GrainType("up")]
public class UpCounterGrain : IUpCounterGrain { /* as above */ }

Det finns flera sätt att lösa den här tvetydigheten som beskrivs i följande underavsnitt.

Tvetydiga korntyper med hjälp av unika markörgränssnitt

Det tydligaste sättet att skilja dessa korn är att ge dem unika korngränssnitt. Om vi till exempel lägger till UpCounterGrain gränssnittet IUpCounterGrain i klassen och lägger till DownCounterGrain gränssnittet IDownCounterGrain i klassen, som i följande exempel, kan vi lösa rätt kornreferens genom att skicka IUpCounterGrain eller IDownCounterGrain till anropet GetGrain<T> i stället för att skicka den tvetydiga ICounterGrain typen.

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
}

Om du vill skapa en referens till något av kornen bör du överväga följande 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");

Kommentar

I föregående exempel skapade du två kornreferenser med samma nyckel, men olika korntyper. Den första, som lagras i variabeln myUpCounter , är en referens till kornet med ID upcounter/my-counter: t . Den andra, som lagras i variabeln myDownCounter , är en referens till kornet med ID downcounter/my-counter: t . Det är kombinationen av korntyp och kornnyckel som unikt identifierar ett korn. Därför och myUpCounter myDownCounter referera till olika korn.

Tvetydiga korntyper genom att tillhandahålla ett prefix för kornklass

Du kan ange ett prefix för kornklassnamn till , till IGrainFactory.GetGrainexempel:

ICounterGrain myUpCounter = grainFactory.GetGrain<ICounterGrain>("my-counter", grainClassNamePrefix: "Up");
ICounterGrain myDownCounter = grainFactory.GetGrain<ICounterGrain>("my-counter", grainClassNamePrefix: "Down");

Ange standardimplementeringen för kornighet med hjälp av namngivningskonventionen

När du gör flera implementeringar av samma korngränssnitt Orleans tvetydiga väljer du en implementering med hjälp av konventionen om att ta bort ett inledande "I" från gränssnittsnamnet. Om till exempel gränssnittsnamnet är ICounterGrain och det finns två implementeringar, CounterGrain och DownCounterGrain, Orleans väljer CounterGrain när du tillfrågas om en referens till ICounterGrain, som i följande exempel:

/// This will refer to an instance of CounterGrain, since that matches the convention.
ICounterGrain myUpCounter = grainFactory.GetGrain<ICounterGrain>("my-counter");

Ange standardtyp för kornighet med hjälp av ett attribut

Attributet Orleans.Metadata.DefaultGrainTypeAttribute kan läggas till i ett kornigt gränssnitt för att ange korntyp för standardimplementeringen för gränssnittet, som i följande exempel:

[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");

Tvetydiga korntyper genom att ange det lösta korn-ID:t

Vissa överlagringar av IGrainFactory.GetGrain accepterar ett argument av typen Orleans.Runtime.GrainId. När du använder dessa överlagringar Orleans behöver du inte mappa från en gränssnittstyp till en korntyp och därför finns det ingen tvetydighet att lösa. Till exempel:

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"));