Принимаем и парсим все
Чтобы обрабатывать сообщения с разными JSON-структурами в NetCore-приложении, принимаемые из RabbitMQ, можно использовать несколько подходов. Вот наиболее распространённые и эффективные решения:
1. Использование System.Text.Json с динамическим парсингом
Если структуры сообщений заранее неизвестны или их много, можно парсить JSON в динамический объект (JsonDocument или JsonElement), а затем анализировать его содержимое.
Пример:
using System.Text.Json;
public void ProcessMessage(string message)
{
using JsonDocument document = JsonDocument.Parse(message);
JsonElement root = document.RootElement;
// Проверяем наличие ключей и обрабатываем в зависимости от структуры
if (root.TryGetProperty("type", out JsonElement typeElement))
{
string type = typeElement.GetString();
switch (type)
{
case "Order":
// Парсим как Order
var order = JsonSerializer.Deserialize<Order>(message);
ProcessOrder(order);
break;
case "User":
// Парсим как User
var user = JsonSerializer.Deserialize<User>(message);
ProcessUser(user);
break;
default:
Console.WriteLine($"Unknown message type: {type}");
break;
}
}
else
{
Console.WriteLine("Message has no 'type' field.");
}
}
2. Использование полиморфного десериализатора
Если сообщения имеют общий дискриминатор (например, поле type), можно использовать полиморфный десериализатор из System.Text.Json или библиотек вроде Newtonsoft.Json.
Пример с System.Text.Json:
public interface IMessage { }
public class Order : IMessage
{
public string Id { get; set; }
// ...
}
public class User : IMessage
{
public string Name { get; set; }
// ...
}
// Настройка десериализатора
var options = new JsonSerializerOptions
{
Converters = { new MessageConverter() }
};
var message = JsonSerializer.Deserialize<IMessage>(jsonString, options);
// Реализация MessageConverter
public class MessageConverter : JsonConverter<IMessage>
{
public override IMessage Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
using JsonDocument doc = JsonDocument.ParseValue(ref reader);
if (doc.RootElement.TryGetProperty("type", out JsonElement type))
{
return type.GetString() switch
{
"Order" => JsonSerializer.Deserialize<Order>(doc.RootElement.GetRawText()),
"User" => JsonSerializer.Deserialize<User>(doc.RootElement.GetRawText()),
_ => throw new JsonException($"Unknown message type: {type}")
};
}
throw new JsonException("Message has no 'type' field.");
}
public override void Write(Utf8JsonWriter writer, IMessage value, JsonSerializerOptions options)
{
JsonSerializer.Serialize(writer, value, value.GetType(), options);
}
}
3. Использование Newtonsoft.Json
Если вы используете Newtonsoft.Json, можно воспользоваться атрибутом [JsonConverter] и реализовать кастомный конвертер.
Пример:
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
public class MessageConverter : JsonConverter
{
public override bool CanConvert(Type objectType) => true;
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jo = JObject.Load(reader);
if (jo["type"] != null)
{
switch (jo["type"].Value<string>())
{
case "Order":
return jo.ToObject<Order>();
case "User":
return jo.ToObject<User>();
default:
throw new JsonException($"Unknown message type: {jo["type"]}");
}
}
throw new JsonException("Message has no 'type' field.");
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize(writer, value);
}
}
// Использование
var settings = new JsonSerializerSettings
{
Converters = { new MessageConverter() }
};
var message = JsonConvert.DeserializeObject<IMessage>(jsonString, settings);
4. Обработка через try-catch
Если структуры сообщений известны, но не имеют общего дискриминатора, можно попробовать десериализовать в разные классы по очереди.
Пример:
public void ProcessMessage(string message)
{
try
{
var order = JsonSerializer.Deserialize<Order>(message);
ProcessOrder(order);
}
catch (JsonException)
{
try
{
var user = JsonSerializer.Deserialize<User>(message);
ProcessUser(user);
}
catch (JsonException)
{
Console.WriteLine("Unknown message format.");
}
}
}Рекомендации:
- Дискриминатор: Если возможно, добавьте поле
typeили аналогичное в JSON-сообщения, чтобы упростить маршрутизацию. - Логирование: Всегда логируйте ошибки парсинга для отладки.
- Производительность: Для высоконагруженных систем предпочтите
System.Text.JsonвместоNewtonsoft.Json.
Только полноправные пользователи могут оставлять комментарии. Аутентифицируйтесь пожалуйста, используя сервисы.