我们的许多消息都需要验证才能安全处理。检查输入,有时应用复杂的业务规则。
在 Akka 之前的设计中,我会有ICommandValidator<T>
一个单一方法IsValid
和一个错误属性。因此,具体的验证器会告诉您消息是否有效,如果不是,您可以阅读错误。
在 Akka.Net 中,我开始为每条消息编写具体的 Validator Actor(显然创建更多的 Actor 是好的)——例如 CreateTenantCommand 由 TenantCreatorActor(从 ReceiveActor 继承)发送到 CreateTenantCommandValidatorActor 进行验证。如果它是有效的,则 CreateTenantCommandValidated 消息(基本上是包装的原始消息)被发送到 TenantCreateActor 并解包消息,然后处理该消息。
我想知道我是否应该将未经验证的消息列表与需要验证的参与者一起存储,然后将这些消息与验证响应相关联,还是应该来回发送整个消息以进行验证?验证器需要验证整个消息,但是我不确定在请求参与者上保持消息完整并仅确认其有效性的好处?
在 Akka.Net 消息和 Actors 中使用泛型是否常见?这似乎是一个包含大量样板的区域,但我从未在任何示例中真正看到过太多泛型,这让我很担心。我的设计看起来像:
public class IsValidCommand<TCommamd>{
public TCommamd Command { get; private set; }
Ctor....
}
public class ValidCommand<TCommamd>
{
public TCommamd Command { get; private set; }
Ctor....
}
public class InvalidCommand<TCommamd>
{
public TCommamd Command { get; private set; }
public List<string> Errors { get; private set; }
Ctor....
}
另一种方法是创建一个组合ValidatedCommand<T>
public class ValidatedCommand<T>
{
public T Command { get; set; }
public IEnumerable<string> Errors { get; }
public bool IsValid => !Errors.Any();
Ctor...
}
然后我可以创建一个通用的 ValidatorActor 并向其中注入一个验证器类。例如
var createValidatorProps = Props.Create(() => new ValidatorActor<CreateInstanceCommand>(Self, new CreateInstanceCommandValidator()));
CreateInstanceCommandValidatorActor = Context.ActorOf(createValidatorProps, "CreateInstanceCommandValidatorActor");
使用通用验证器参与者,例如:
public class ValidatorActor<T> : ReceiveActor{
public IActorRef Requestor { get; }
public ValidatorActor(IActorRef requestor, ICommandValidator<T> validator)
{
Requestor = requestor;
Receive<IsValidCommand<T>>(
commandWrapper =>
{
var command = commandWrapper.Command;
if (validator.Validate(command))
{
requestor.Tell(new ValidCommand<T>(command));
}
else
{
requestor.Tell(new InvalidCommand<T>(command));
}
});
}
}
可能应该注意我意识到它可能应该是这样ValidateAsync
,然后PipeTo
演员就不会阻止。所以这可能需要ValidatedCommand<T>
从 ValidateAsync 方法返回的方法
这意味着这些消息可以标准化。这是在 Akka.Net 中处理消息验证的合适方法还是我完全错了?