Delen via


Korrelverwijzingen

Voordat u een methode op graan aanroept, hebt u eerst een verwijzing naar dat graan nodig. Een korrelverwijzing is een proxyobject dat dezelfde graaninterface implementeert als de bijbehorende graanklasse. De logische identiteit (type en unieke sleutel) van de doelkorrel wordt ingekapseld. Korrelverwijzingen worden gebruikt voor het aanroepen van het doelgran. Elke korrelverwijzing is naar één korrel (één exemplaar van de graanklasse), maar er kunnen meerdere onafhankelijke verwijzingen naar hetzelfde graan worden gemaakt.

Omdat een korrelreferentie de logische identiteit van de doelkorrel vertegenwoordigt, is deze onafhankelijk van de fysieke locatie van het graan en blijft deze geldig, zelfs na een volledige herstart van het systeem. Ontwikkelaars kunnen korrelverwijzingen gebruiken zoals elk ander .NET-object. Deze kan worden doorgegeven aan een methode, gebruikt als retourwaarde voor methoden en zelfs worden opgeslagen in permanente opslag.

Een korrelreferentie kan worden verkregen door de identiteit van een graan door te geven aan de IGrainFactory.GetGrain<TGrainInterface>(Type, Guid) methode, waarbij T de graaninterface en key de unieke sleutel van het graan binnen het type is.

Hier volgen enkele voorbeelden van het verkrijgen van een korrelreferentie van de IPlayerGrain hierboven gedefinieerde interface.

Vanuit een graanklasse:

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

Vanuit Orleans clientcode:

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

Korrelverwijzingen bevatten drie stukjes informatie:

  1. Het graantype, dat de graanklasse uniek identificeert.
  2. De graansleutel, die een logisch exemplaar van die graanklasse uniek identificeert.
  3. De interface die de korrelreferentie moet implementeren.

Notitie

Het korreltype en de sleutel vormen de graanidentiteit.

U ziet dat de bovenstaande aanroepen om slechts twee van deze drie dingen te IGrainFactory.GetGrain accepteren:

  • De interface die wordt geïmplementeerd door de korrelreferentie, IPlayerGrain.
  • De graansleutel, die de waarde is van playerId.

Ondanks dat een korrelreferentie een graantype, sleutel en interface bevat, worden de voorbeelden alleen geleverd Orleans met de sleutel en interface. Dat komt doordat Orleans een toewijzing tussen graaninterfaces en graantypen wordt onderhouden. Wanneer u de graanfabriek om IShoppingCartGrainvraagt, Orleans raadpleegt u de toewijzing om het bijbehorende graantype te vinden, zodat deze de verwijzing kan maken. Dit werkt wanneer er slechts één implementatie van een graaninterface is, maar als er meerdere implementaties zijn, moet u deze in de GetGrain aanroep ondubbelzinnig maken. Zie voor meer informatie de volgende sectie, het ondubbelzinnig maken van de resolutie van het graantype.

Notitie

Orleans genereert grain reference-implementatietypen voor elke grain-interface in uw toepassing tijdens de compilatie. Deze grain reference-implementaties nemen over van de Orleans.Runtime.GrainReference klasse. GetGrain retourneert exemplaren van de gegenereerde Orleans.Runtime.GrainReference implementatie die overeenkomt met de aangevraagde graaninterface.

Ondubbelzinnige korreltyperesolutie

Wanneer er meerdere implementaties van een graaninterface zijn, zoals in het volgende voorbeeld, Orleans wordt geprobeerd de beoogde implementatie te bepalen bij het maken van een korrelreferentie. Bekijk het volgende voorbeeld, waarin er twee implementaties van de ICounterGrain interface zijn:

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
}

Met de volgende aanroep wordt GetGrain een uitzondering gegenereerd, omdat Orleans u niet weet hoe u ondubbelzinnig kunt toewijzen ICounterGrain aan een van de graanklassen.

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

Er System.ArgumentException wordt een bericht gegenereerd met het volgende bericht:

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

In het foutbericht wordt aangegeven welke grain-implementaties Orleans overeenkomen met het aangevraagde type korrelinterface. ICounterGrain Hier ziet u de graantypenamen (upcounter en downcounter) evenals de graanklassen (UpCounterGrain en DownCounterGrain).

Notitie

De korreltypenamen in het voorgaande foutbericht en upcounter worden afgeleid van respectievelijk de graanklassenamen UpCounterGrain DownCounterGrain.downcounter Dit is het standaardgedrag waarin Orleans het kan worden aangepast door een [GrainType(string)] kenmerk toe te voegen aan de graanklasse. Voorbeeld:

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

Er zijn verschillende manieren om deze dubbelzinnigheid op te lossen die in de volgende subsecties worden beschreven.

Eenduidige graantypen met behulp van unieke markeringsinterfaces

De helderste manier om deze korrels ondubbelzinnig te maken, is door ze unieke graaninterfaces te geven. Als we bijvoorbeeld de interface IUpCounterGrain toevoegen aan de UpCounterGrain klasse en de interface IDownCounterGrain toevoegen aan de DownCounterGrain klasse, zoals in het volgende voorbeeld, kunnen we de juiste korrelreferentie oplossen door de aanroep door IUpCounterGrain te geven of IDownCounterGrain aan de GetGrain<T> aanroep door te geven in plaats van het dubbelzinnige ICounterGrain type door te geven.

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
}

Als u een verwijzing naar een van beide korrels wilt maken, moet u rekening houden met de volgende code:

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

Notitie

In het voorgaande voorbeeld hebt u twee korrelverwijzingen gemaakt met dezelfde sleutel, maar verschillende graantypen. De eerste, opgeslagen in de myUpCounter variabele, is een verwijzing naar het graan met de id upcounter/my-counter. De tweede, opgeslagen in de myDownCounter variabele, is een verwijzing naar het graan met de id downcounter/my-counter. Het is de combinatie van graantype en graansleutel die een graan uniek identificeren. myUpCounter Daarom, en myDownCounter verwijzen naar verschillende korrels.

Ondubbelzinnige graantypen door een voorvoegsel voor de graanklasse op te geven

U kunt een voorvoegsel voor de naam van een graanklasse opgeven, IGrainFactory.GetGrainbijvoorbeeld:

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

De standaardinterval-implementatie opgeven met behulp van de naamconventie

Wanneer u meerdere implementaties van dezelfde graaninterface ondubbelzinnig maakt, Orleans selecteert u een implementatie met behulp van de conventie voor het strippen van een voorloop-I uit de interfacenaam. Als de interfacenaam bijvoorbeeld is ICounterGrain en er twee implementaties zijn en CounterGrain DownCounterGrain, Orleans wordt gekozen CounterGrain wanneer u wordt gevraagd om een verwijzing naar ICounterGrain, zoals in het volgende voorbeeld:

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

Het standaardkorreltype opgeven met behulp van een kenmerk

Het Orleans.Metadata.DefaultGrainTypeAttribute kenmerk kan worden toegevoegd aan een graaninterface om het graantype van de standaard implementatie voor die interface op te geven, zoals in het volgende voorbeeld:

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

Ondubbelzinnige graantypen door de opgeloste graan-id op te geven

Sommige overbelastingen van IGrainFactory.GetGrain het accepteren van een argument van het type Orleans.Runtime.GrainId. Wanneer u deze overbelastingen gebruikt, Orleans hoeft u niet toe te wijzen van een interfacetype naar een graantype en hoeft er dus geen dubbelzinnigheid te worden opgelost. Voorbeeld:

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