尝试创建一个相当简单的发件箱模式,而不依赖于外部库。我想要完成的核心事情是处理暂时性故障。我使用 CQRS 和 Mediatr 来保持视图数据库与事务数据库的最终一致性。我通过处理程序通过进程内事件更新视图数据库。 (例如 UserCreatedEvent -> UserCreatedEventHandler)
为了确保事件不会因瞬时故障而丢失,我将它们存储在数据库中并通过后台进程发布它们。由于处理程序被键入到一个类中,因此只会执行一个处理程序(UserCreatedEvent 由 UserCreatedEventHandler 处理)。
我可以在一个项目中定义 X 个事件类型,并且它们在属性方面都是相互独立的。它们都有一个通用的标记界面(INotification)。为了处理瞬时故障,在保存事务数据库时,我序列化事件并存储在数据库中,如下所示。
public record SampleMessage(string Value, string Type);
//serialization
string typeOfNotification = typeof(T).AssemblyQualifiedName;
SampleMessage message = new(JsonSerializer.Serialize(content), typeOfNotification);
//deserialization
Type messageType = Type.GetType(message.Type)
var dvalue = JsonSerializer.Deserialize(message.Value, messageType);
await publisher.Publish(dvalue);
我非常关心在对象中存储类型信息。我最终可能会从将它们存储在数据库中转向将它们发布到代理并通过外部系统进行处理。我相信由于存在漏洞,也不再推荐存储类型。什么是可维护的良好替代方案?
我的一个想法是存储一个“Type”枚举,它只存储与事件相关的内容(例如 UserCreated)
public record SampleMessage(string Value, MessageType Type);
public MessageType { UserCreated, UserDeleted };
//deserialize
var result = switch content.Type
{
UserCreated=> JsonSerializer.Deserialize<UserCreatedEvent>(content)
_ => //Throw exception
}
这相当简单,但我最终会得到大量的 switch 语句,并在每次添加新事件时修改它。我看到的与此相关的大多数答案都是使用自定义转换器,但它们主要用于多态反序列化(例如,使用 json.net 在没有类型信息的情况下反序列化多态 json 类)。我需要反序列化为没有任何继承的非多态类型对象。
这方面的最佳实践是什么?
dotnet 的原生 JSON 库有一个有趣的方法来解决这个问题,我想说它也可以用于您的情况。
以这个基于
System.Text.Json
版本 7+ 和 dotnet 8 的示例为例:
using System.Text.Json.Serialization;
[JsonDerivedType(typeof(Cat), "cat")]
[JsonDerivedType(typeof(Dog), "dog")]
class Animal
{
public string Name { get; set; }
}
class Cat : Animal;
class Dog : Animal;
序列化器在生成的 JSON 中使用 $type
属性,读取为“cat”或“dog”,并且在反序列化 JSON 时,它可以安全地依赖
$type
将 JSON 映射到目标类型,因为它是一个为该类型明确定义的鉴别器名称,并且它不能用于恶意加载目标类型来代替
Cat
或
Dog
次。现在,以该示例为例,由于您提到您的结构中已经有
INotification
标记,因此您也许可以直接利用
System.Text.Json
并解决漏洞。但是,如果您的设置不允许您直接执行此操作,您将能够自己实现类似的解决方案。
NotificationDiscriminatorAttribute
接受鉴别器名称。
$type
或
$discriminator
来存储使用反射提取的类型的鉴别器名称。
JsonSerializer.Deserialize(message.Value, messageType);
) 消息相同的方法,但这次使用
$type
或
$discriminator
从您在步骤 3 中创建的字典中提取目标类型以进行反序列化。