Codename Orleans – Using Generics with Grains

In Orleans you can use generics with grain interfaces:

public interface IGenericGrain<T> : Orleans.IGrain
{
    Task SetValue(T value);

    Task GetValue();
}

When you talk to this grain from a client application, you can specify the value of ‘T’ on the factory class:

var grain1 = GenericGrainFactory<int>.GetGrain(1);
await grain1.SetValue(123);
await grain1.GetValue();

var grain2 = GenericGrainFactory<string>.GetGrain(2);
await grain2.SetValue("foo");
await grain2.GetValue();

You can even extend ‘T’ to the persistence layer:

public interface IMyGrainState<T> : IGrainState
{
    T Value { get; set; }
}

[StorageProvider(ProviderName = "AzureStore")]
public class GenericGrain<T> : Orleans.GrainBase<IMyGrainState<T>>, IDbGrain<T>
{
    public Task SetValue(T value)
    {
        this.State.Value = value;
        return this.State.WriteStateAsync();
    }

    public Task GetValue()
    {
        return Task.FromResult(this.State.Value);
    }
}

This seems to work well for value types such as string, int, double etc…

One word of caution; make sure that you always use the same value for ‘T’ when dealing with a particular grain ID, otherwise you’ll get cast exceptions.

Advertisements