Compartilhar via


Extensões de grão

As extensões de grão fornecem uma maneira de adicionar comportamento extra aos grãos. Ao estender um grão com uma interface derivada de IGrainExtension, você pode adicionar novos métodos e funcionalidades ao grão.

Neste artigo, você verá dois exemplos de extensões de grão. O primeiro exemplo mostra como adicionar um método Deactivate a todos os grãos que podem ser usados para desativar o grão. O segundo exemplo mostra como adicionar um método GetState e SetState a qualquer grão, permitindo manipular o estado interno do grão.

Exemplo de desativação de extensão

Neste exemplo, você aprenderá a adicionar um método Deactivate a todos os grãos automaticamente. O método pode ser usado para desativar o grão e aceita uma cadeia de caracteres como parâmetro de mensagem. Os grãos Orleans já dão suporte a essa funcionalidade por meio da interface IGrainManagementExtension. No entanto, este exemplo serve para mostrar como você pode adicionar essa funcionalidade ou semelhante por conta própria.

Desativar interface de extensão

Comece definindo uma interface IGrainDeactivateExtension, que contém o método Deactivate. A interface deve derivar de IGrainExtension.

public interface IGrainDeactivateExtension : IGrainExtension
{
    Task Deactivate(string msg);
}

Desativar a implementação da extensão

Em seguida, implemente a classe GrainDeactivateExtension, que fornece a implementação para o método Deactivate.

Para acessar o grão de destino, você recupera o IGrainContext do construtor. Ele é injetado ao criar a extensão com injeção de dependência.

public sealed class GrainDeactivateExtension : IGrainDeactivateExtension
{
    private IGrainContext _context;

    public GrainDeactivateExtension(IGrainContext context)
    {
        _context = context;
    }

    public Task Deactivate(string msg)
    {
        var reason = new DeactivationReason(DeactivationReasonCode.ApplicationRequested, msg);
        _context.Deactivate(reason);
        return Task.CompletedTask;
    }
}

Desativar o registro e o uso da extensão

Agora que você definiu a interface e a implementação, registre a extensão ao configurar o silo com o método AddGrainExtension.

siloBuilder.AddGrainExtension<IGrainDeactivateExtension, GrainDeactivateExtension>();

Para usar a extensão em qualquer grão, recupere uma referência à extensão e chame o método Deactivate.

var grain = client.GetGrain<SomeExampleGrain>(someKey);
var grainReferenceAsInterface = grain.AsReference<IGrainDeactivateExtension>();

await grainReferenceAsInterface.Deactivate("Because, I said so...");

Exemplo de extensão de manipulação de estado

Neste exemplo, você aprenderá a adicionar um método GetState e SetState a qualquer grão por meio de extensões, permitindo manipular o estado interno do grão.

Interface de extensão de manipulação de estado

Primeiro, defina a interface IGrainStateAccessor<T>, que contém os métodos GetState e SetState. Novamente, essa interface deve derivar de IGrainExtension.

public interface IGrainStateAccessor<T> : IGrainExtension
{
    Task<T> GetState();
    Task SetState(T state);
}

Depois de ter acesso ao grão de destino, você pode usar a extensão para manipular seu estado. Neste exemplo, você usa uma extensão para acessar e modificar um valor de estado inteiro específico dentro do grão de destino.

Implementação da extensão de manipulação de estado

A extensão usada é IGrainStateAccessor<T>, que fornece métodos para obter e definir um valor de estado do tipo T. Para criar a extensão, implemente a interface em uma classe que usa um getter e um setter como argumentos em seu construtor.

public sealed class GrainStateAccessor<T> : IGrainStateAccessor<T>
{
    private readonly Func<T> _getter;
    private readonly Action<T> _setter;

    public GrainStateAccessor(Func<T> getter, Action<T> setter)
    {
        _getter = getter;
        _setter = setter;
    }

    public Task<T> GetState()
    {
        return Task.FromResult(_getter.Invoke());
    }

    public Task SetState(T state)
    {
        _setter.Invoke(state);
        return Task.CompletedTask;
    }
}

Na implementação anterior, a classe GrainStateAccessor<T> usa argumentos getter e setter em seu construtor. Esses delegados são usados para ler e modificar o estado do grão de destino. O método GetState() retorna um Task<TResult> e encapsula o valor atual do estado T, enquanto o método SetState(T state) define o novo valor do estado T.

Uso e registro da extensão de manipulação de estado

Para usar a extensão para acessar e modificar o estado da granularidade de destino, você precisa registrar a extensão e definir seus componentes no método Grain.OnActivateAsync() da granularidade de destino.

public override Task OnActivateAsync()
{
    // Retrieve the IGrainStateAccessor<T> extension
    var accessor = new GrainStateAccessor<int>(
        getter: () => this.Value,
        setter: value => this.Value = value);

    // Set the extension as a component of the target grain's context
    ((IGrainBase)this).GrainContext.SetComponent<IGrainStateAccessor<int>>(accessor);

    return base.OnActivateAsync();
}

No exemplo anterior, você cria uma instância de GrainStateAccessor<int> que usa um getter e um setter para um valor de estado inteiro. O getter lê a propriedade Value da granularidade de destino, enquanto o setter define o novo valor da propriedade Value. Em seguida, você define essa instância como um componente do contexto do grão de destino usando o método IGrainContext.SetComponent.

Depois que a extensão for registrada, você poderá usá-la para obter e definir o estado do grão de destino acessando-a por meio de uma referência à extensão.

// Get a reference to the IGrainStateAccessor<int> extension
var accessor = grain.AsReference<IGrainStateAccessor<int>>();

// Get the current value of the state
var value = await accessor.GetState();

// Set a new value of the state
await accessor.SetState(10);

No exemplo anterior, você obtém uma referência à extensão IGrainStateAccessor<int> para uma instância de grão específica usando o método GrainExtensions.AsReference. Em seguida, você pode usar essa referência para chamar os métodos GetState() e SetState(T state) para ler e modificar o valor de estado do grão de destino.

Confira também