简体   繁体   中英

Multiple implementations of same grain interface using Orleans

I have an Orleans applications with the following structure:

public interface IGraintest : Orleans.IGrainWithGuidCompoundKey
{
    Task Init();
}



public abstract class GraintestImpl<T> : Grain, IGraintest, Deserializer<T>
{
    string streamName;
    public Task Init()
    {
        return Task.CompletedTask;
    }


    public override async Task OnActivateAsync()
    {
        var primaryKey = this.GetPrimaryKey(out streamName);
        var streamProvider = GetStreamProvider("SMSProvider");
        var stream = streamProvider.GetStream<String>(primaryKey, streamName);

        // To resume stream in case of stream deactivation
        var subscriptionHandles = await stream.GetAllSubscriptionHandles();

        if (subscriptionHandles.Count > 0)
        {
            foreach (var subscriptionHandle in subscriptionHandles)
            {
                await subscriptionHandle.ResumeAsync(OnNextMessage);
            }
        }

        await stream.SubscribeAsync(OnNextMessage);
    }

    public abstract T Process(string l);

    private Task OnNextMessage(string message, StreamSequenceToken sequenceToken)
    {
        T obj = Process(message);
        //gonna do something with obj here
        return Task.CompletedTask;
    }
}
public class ProcessImplA: GraintestImpl<Car>
{
    public override Car Process(string l)
    {
        return new Car(l);  
    }
}
public class ProcessImplB: GraintestImpl<Boat>
{
    public override Boat Process(string l)
    {
        return new Boat(l);
    }
}

Here I have a grain that I use to read messages from a stream and apply some operation to them. Since I have different object types I want to work with I created an abstract class to implement the interface. The problem lies here:

var sourceOne = client.GetGrain<IGraintest>(guid, "Car");
var sourceTwo = client.GetGrain<IGraintest>(guid, "Boat");

When I run the program like this I get the error code:

Exception while trying to run client: Cannot resolve grain interface ID=-<blabla> to a grain class because of multiple implementations of it

So my question is, can I do a minor change to make this work or do I have to create a grain interface for each ProcessImpl grain that I want to utilize?

You can disambiguate the GetGrain call by using an overload which accepts a grain class name prefix.

var sourceOne = client.GetGrain<IGraintest>(guid, "Car", grainClassNamePrefix: "MyNamespace.ProcessImplA");
var sourceTwo = client.GetGrain<IGraintest>(guid, "Boat", grainClassNamePrefix: "MyNamespace.ProcessImplB");

Otherwise, if there are two implementations of the interface then the runtime does not know how to decide which one to use. Importantly for your case, the information about which class implements which constructed generic interface is not known to the IGrainFactory implementation, so it is not able to pick an implementation.

Another approach is to add a marker interface to your grain classes, for example, you could have IGrainTestImplBoat :

public interface IGrainTestImplBoat : Orleans.IGrainWithGuidCompoundKey { }

public class ProcessImplB : GraintestImpl<Boat>, IGrainTestImplBoat { /* ... */ }

var sourceTwo = client.GetGrain<IGrainTestImplBoat>(guid, "Boat");

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM