使用 Orleans 实现相同粒度接口的多个实现
Multiple implementations of same grain interface using Orleans
我有一个具有以下结构的 Orleans 应用程序:
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);
}
}
这里我有一个 grain,我用它来从流中读取消息并对它们应用一些操作。由于我有不同的对象类型,我想使用我创建了一个抽象 class 来实现接口。
问题出在这里:
var sourceOne = client.GetGrain<IGraintest>(guid, "Car");
var sourceTwo = client.GetGrain<IGraintest>(guid, "Boat");
当我 运行 这样的程序时,我得到错误代码:
Exception while trying to run client: Cannot resolve grain interface ID=-<blabla> to a grain class because of multiple implementations of it
所以我的问题是,我可以做一个小改动来完成这项工作,还是我必须为我想使用的每个 ProcessImpl grain 创建一个 grain 接口?
您可以使用接受 grain class 名称前缀的重载来消除 GetGrain
调用的歧义。
var sourceOne = client.GetGrain<IGraintest>(guid, "Car", grainClassNamePrefix: "MyNamespace.ProcessImplA");
var sourceTwo = client.GetGrain<IGraintest>(guid, "Boat", grainClassNamePrefix: "MyNamespace.ProcessImplB");
否则,如果接口有两个实现,那么运行时不知道如何决定使用哪一个。对于您的情况重要的是,IGrainFactory
实现不知道关于哪个 class 实现哪个构造的通用接口的信息,因此它无法选择一个实现。
另一种方法是在你的 grain classes 中添加一个标记界面,例如,你可以 IGrainTestImplBoat
:
public interface IGrainTestImplBoat : Orleans.IGrainWithGuidCompoundKey { }
public class ProcessImplB : GraintestImpl<Boat>, IGrainTestImplBoat { /* ... */ }
var sourceTwo = client.GetGrain<IGrainTestImplBoat>(guid, "Boat");
我有一个具有以下结构的 Orleans 应用程序:
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);
}
}
这里我有一个 grain,我用它来从流中读取消息并对它们应用一些操作。由于我有不同的对象类型,我想使用我创建了一个抽象 class 来实现接口。 问题出在这里:
var sourceOne = client.GetGrain<IGraintest>(guid, "Car");
var sourceTwo = client.GetGrain<IGraintest>(guid, "Boat");
当我 运行 这样的程序时,我得到错误代码:
Exception while trying to run client: Cannot resolve grain interface ID=-<blabla> to a grain class because of multiple implementations of it
所以我的问题是,我可以做一个小改动来完成这项工作,还是我必须为我想使用的每个 ProcessImpl grain 创建一个 grain 接口?
您可以使用接受 grain class 名称前缀的重载来消除 GetGrain
调用的歧义。
var sourceOne = client.GetGrain<IGraintest>(guid, "Car", grainClassNamePrefix: "MyNamespace.ProcessImplA");
var sourceTwo = client.GetGrain<IGraintest>(guid, "Boat", grainClassNamePrefix: "MyNamespace.ProcessImplB");
否则,如果接口有两个实现,那么运行时不知道如何决定使用哪一个。对于您的情况重要的是,IGrainFactory
实现不知道关于哪个 class 实现哪个构造的通用接口的信息,因此它无法选择一个实现。
另一种方法是在你的 grain classes 中添加一个标记界面,例如,你可以 IGrainTestImplBoat
:
public interface IGrainTestImplBoat : Orleans.IGrainWithGuidCompoundKey { }
public class ProcessImplB : GraintestImpl<Boat>, IGrainTestImplBoat { /* ... */ }
var sourceTwo = client.GetGrain<IGrainTestImplBoat>(guid, "Boat");