我开始用boot-camp查看Akka.Net框架。
我可以理解基本的Actor概念和使用事件源的持久性。
我很难理解域事件将如何被其他参与者发送和接收。
限制单个系统本地部署的Actors和No DI容器和 使用c#/ ASPP.NET API,我将每个AgreegateRoot分成它自己的项目
我正在概念化像
这样的东西ManagerActor
Manager Actor将收到命令消息并通过验证过程,如果验证将被发送到AggregateRoot Actor。将在根或子actor中生成事件。
请告知以下内容:
要在实体内部发布类似于eventbus的事件,我可以使用以下语法吗?
Context.System.EventStream.Publish(MyEvent);
订阅活动我明白语法是
System.EventStream.Subscribe( subscriber,MyEvent)
我希望Actor发布的事件由Handlers(其他Actors)处理,其中当前的AggregateRoot Actor或Child Entity内部应该不知道。
这是我完全陷入困境的地方。这是如何实现的?
System.EventStream.Subscribe中的订户是IActorRef。为了得到这个,我需要了解课程。
我应该创建一个启动引导程序,它将引用所有项目/ AggregateRoots并在那里构建消息类型的订阅吗?
我试图找到博客或文章,但没有太多运气。
先谢谢。
答案 0 :(得分:1)
另一个解决方案是使用Akka.Cluster.Sharding,这对于这个用例是完美的。然而;我将承认群集分片不是一个初学者主题。群集分片允许您设置如何通过道具创建actor以及将消息映射到特定的实体"的策略。
以下是我上面链接的博客文章中示例的角色分片设置示例:
using(var system = ActorSystem.Create("cluster-system"))
{
var sharding = ClusterSharding.Get(system);
var shardRegion = sharding.Start(
typeName: nameof(MyActor),
entityProps: Props.Create<MyActor>(), // the Props used to create entities
settings: ClusterShardingSettings.Create(system),
messageExtractor: new MessageExtractor(maxNumberOfNodes * 10)
);
// ... etc
}
然后你可以发送这样的信息:
region.Tell(new ShardEnvelope("<entity-id>", new MyMessage()));
上面提到的消息提取器是使这一切全部工作的关键组件。消息提取器允许您将消息映射到特定实体(实际上是entityId)。因此,如果您的消息例如都具有目标实体的Id,那么这变得简单。这是一个示例消息提取器(再次来自petabridge博客文章和Akka.Net代码库):
public sealed class MessageExtractor : HashCodeMessageExtractor
{
public MessageExtractor(int maxNumberOfShards) : base(maxNumberOfShards) { }
public override string EntityId(object message) =>
(message as ShardEnvelope)?.EntityId;
public override object EntityMessage(object message) =>
(message as ShardEnvelope)?.Payload;
}
public sealed class ShardEnvelope
{
public readonly string EntityId;
public readonly object Payload;
public ShardEnvelope(string entityId, object payload)
{
EntityId = entityId;
Payload = payload;
}
}
我承认这似乎有点过分,如果在Akka.Net中为虚拟演员提供更好的一流支持,我认为这将得到纠正。
答案 1 :(得分:0)
我将每个AgreegateRoot分成了自己的项目
我不会为每个AggregateRoot创建一个单独的项目,这对我来说似乎有些过分。你有什么收获的?你可以使用一个类/ actor,不需要一个完全独立的项目。
听起来您可能会对如何引用代表您的事件的C#类型感到困惑,如果每个AggregateRoot都有一个单独的项目,那么这并不令人惊讶 - 您将很快遇到循环引用。尝试从单个项目开始,使用文件夹分隔有界上下文。在每个文件夹中,创建您需要的任何聚合以及它们负责的任何事件。这样,所有参与者都可以看到所有事件类型。一旦这种增长/变得无法管理,您可以将其分解为单独的项目,这类似于:
请注意,您的演员生成和订阅的事件代表整个系统中的一种公共合同/ API。将它们作为单独的DLL如上所述避免了循环引用(因为.Events项目不引用任何东西)。因此,在此结构中,MyApp.BoundedContext1
可以引用MyApp.BoundedContext1.Events
并发布它们。 MyApp.BoundedContext2
也可以引用MyApp.BoundedContext1.Events
并订阅它们。
我希望Actor发布的事件由Handlers(其他Actors)处理,其中当前的AggregateRoot Actor或Child Entity内部应该不知道。
这是我完全陷入困境的地方。这是如何实现的?
您的发布商不需要订阅者的知识。发布者只是向EventStream发布消息。定义参与者和事件类型的上下文应该是相同的(即发布者应该拥有他们的事件类型)。例如,如果您有ValidationActor
发布ThingValidated
个事件,则它们都应位于相同的上下文中。
System.EventStream.Subscribe中的订户是IActorRef。为了得到这个,我需要了解课程。
哪个班?订户已经了解自己。您只需使用Self
即可获得IActorRef
。如果您的意思是事件类,那么请参阅上面有关如何构建项目以引用它的内容。
一旦创建了一个actor,它就可以注册它感兴趣的任何事件类型 - 如果你需要,可以将这些代码放在actor本身的初始化代码中,或者如果你有某种类型的单身演员,如果你愿意,可以使用bootstrapper函数。