【发布时间】:2022-01-13 20:29:05
【问题描述】:
我有一个 .net 应用程序在后台运行并侦听 Kafka 消息的用例。我将收到来自 Kafka 的各种有效载荷/消息。每个有效负载具有不同的结构并包含不同的项目。对于每个有效负载,我们必须将其反序列化为自己的实体(并不总是一对一映射,在某些情况下有效负载到实体可能存在一些映射逻辑),每个实体在数据库中都有自己的表。所以,在反序列化之后,这些实体必须保存在数据库中,同时发送到另一个 Kafka 主题。
总的来说,我将整个流程分为维护 SRP 的 3 个部分。一是反序列化,二是数据库保存,三是Kafka。
我目前正在实现反序列化,如下所示:
第一个有效载荷示例:
{
"type":"fuel",
"data":{
"fueltype":"petrol",
"mileage":23.76,
"tankcapacity":37
}
}
{
"type":"engine",
"data":{
"enginetype":"K series",
"maxpower":88.50,
"displacement":1197
}
}
因此这些消息使用 type
进行区分对于我想为每种类型使用单独的解析器的代码
public interface IJsonParser
{
Payload Parse(dynamic data);
}
public class FuelParser : IJsonParser
{
public Payload Parse(dynamic payload)
{
Fuel f = new Fuel();
f.Mileage = (float)payload.data.mileage;
return f;
}
}
public class EngineParser : IJsonParser
{
public Payload Parse(dynamic data)
{
Engine e = new Engine();
return e;
}
}
public class Payload
{
public int Id { get; set; }
}
public class Fuel : Payload
{
public string FuelType { get; set; }
public float Mileage { get; set; }
public int TankCapacity { get; set; }
}
public class Engine : Payload
{
public string EngineType { get; set; }
public float MaxPower { get; set; }
public int Displacement { get; set; }
}
public static class JsonParserFactory
{
public static IJsonParser GetJsonParser(string type)
{
switch (type)
{
case "fuel":
return new FuelParser();
case "engine":
return new EngineParser();
default:
return null;
}
}
}
string message = "{\r\n\t\"type\": \"fuel\",\r\n\t\"data\":\r\n\t\t{\r\n\t\t\t\"fueltype\": \"petrol\",\r\n\t\t\t\"mileage\": 23.76,\r\n\t\t\t\"tankcapacity\": 37\r\n\t\t}\r\n}";
dynamic data = JsonConvert.DeserializeObject<object>(message);
IJsonParser parser = JsonParserFactory.GetJsonParser(data.type.ToString());
var model = parser.Parse(data);// This model will then be saved in DB as well as sent to another Kafka topic which is the 2nd and 3rd part of the flow.
因此,根据我创建的类型,我创建了一个正在创建单个解析器的工厂。
如果这是一个好的设计,我只是想要建议。我唯一担心的是,未来会有多种类型的有效载荷出现,这将增加解析器的数量。
有什么建议吗?
【问题讨论】:
-
我正在考虑将数据定义为动态的,然后使用 Automapper 根据类型将数据映射到每个实体
-
在某些情况下,我需要在将有效负载数据映射到实体数据之前编写一些逻辑。我们可以在 automapper 中定义自定义映射逻辑吗?我创建了这些基于类型的解析器,只为每种解析器类型编写这些自定义逻辑。
-
是的,你可以在地图定义codewithmukesh.com/blog/automapper-in-aspnet-core/…很多逻辑
-
但是使用 automapper 会是更好的设计,因为我必须根据类型创建映射。因此,只需在类型上使用条件即可创建相应的映射。因为这将在一个类中创建如此多的条件和自动映射器代码。因为我真正关心的不是映射,而是如何以更好的方式构造代码,以便对将从 Kafka 收到的任何消息类型进行反序列化
-
这是一个小细节,但我更愿意将刺痛解析为
JObject-JObject.Parse(message);而不是使用dynamic。dynamic并不总是邪恶的,但是一旦你介绍它,它就有一种传播方式。人们看到它并开始用它做坏事。实际上他们用JObject做同样的事情。
标签: c# json .net asp.net-core design-patterns