Azri Zakaria
Azri Zakaria

Reputation: 1364

Deserialize with dynamic object JSON by following type of content - C#

I have JSON string with different object depends on type of message. Example :

Text

{
"message": {
    "name": "sender",
    "from": "60123456789",
    "id": "ABGGYBJlBxcPAgo6zXukA7i8jnSe",
    "timestamp": "1585125726",
    "type": "text",
    "text": {
        "body": "Hi"
    }
}

Image

{
"message": {
    "name": "sender",
    "from": "60123456789",
    "id": "ABGGYBJlBxcPAgo6zXukA7i8jnSe",
    "timestamp": "1585125726",
    "type": "image",
    "image": {
        "mime_type": "image/jpeg",
        "link": "http://lala.com/Files/image.jpeg",
        "caption": "your image caption"
    }
}

And many more. The key such name, from, id and others is still same.

So what I do in code, I have to create objects for each type :

Object for Text

public class InboundMessageText
{
    public Message Message { get; set; }
}


public class Message
{
    public string Name { get; set; }
    public string From { get; set; }
    public string Id { get; set; }
    public int Timestamp { get; set; }
    public string Type { get; set; }
    public TextMessage Text { get; set; }
}

public class TextMessage
{
    public string Body { get; set; }
}

Object for Image

public class InboundMessageImage
{
    public Message Message { get; set; }
}


public class Message
{
    public string Name { get; set; }
    public string From { get; set; }
    public string Id { get; set; }
    public int Timestamp { get; set; }
    public string Type { get; set; }
    public ImageMessage Image{ get; set; }
}

public class ImageMessage
{
    public string Mime_Type { get; set; }
    public string Link { get; set; }
    public string Caption { get; set; }
}

This how I deserialize

var inboundMessage = JsonConvert.DeserializeObject <InboundMessageText> ("json string");


var addInboundMessage = new Data.Domain.InboundMessage {
    From = inboundMessage.Message.From,
    Name = inboundMessage.Message.Name,
    MessageId = inboundMessage.Message.Id,
    MessageTimestamp = DateTimeOffset.FromUnixTimeSeconds(inboundMessage.Message.Timestamp).LocalDateTime,
};

if (inboundMessage.Message.Type == "text") {        

    addInboundMessage.InboundType = InboundType.Text;
    addInboundMessage.Text = inboundMessage.Message.TextMessage.Body;

}
else if (inboundMessage.Message.Type == "image") {
    //So here I have to deserialize again for image object

    var inboundMessageImage = JsonConvert.DeserializeObject <InboundMessageImage>("json string");

    addInboundMessage.InboundType = InboundType.Image;

    //Business logic   
}
//and many type more...

The code is working, but I have more than 7 types of message so make it my code is to long.

It's that possible to simplify the code?

Upvotes: 1

Views: 323

Answers (2)

Pavel Anikhouski
Pavel Anikhouski

Reputation: 23228

You can manage a base class for any message, and classes for specific types (text, image, etc), like that.

public class BaseMessage
{
    public string Name { get; set; }
    public string From { get; set; }
    public string Id { get; set; }
    public int Timestamp { get; set; }
    public string Type { get; set; }
}

public class ImageMessage : BaseMessage
{
    public ImageMessageContent Image { get; set; }
}

public class TextMessage : BaseMessage
{
    public TextMessageContent Text { get; set; }
}

public class ImageMessageContent
{
    public string Mime_Type { get; set; }
    public string Link { get; set; }
    public string Caption { get; set; }
}

public class TextMessageContent
{
    public string Body { get; set; }
}

Note, that I've slightly changed the naming of your classes. There is no need to create a separate class for every type of message and container for that.

After that you can parse your JSON string to JObject, get the type value and create a concrete Message instance according to this value using ToObject<T> method

var json = JObject.Parse(jsonString);
var type = json["message"]?["type"]?.Value<string>();

BaseMessage message;
switch (type)
{
    case "text":
        message = json["message"]?.ToObject<TextMessage>();
        break;
    case "image":
        message = json["message"]?.ToObject<ImageMessage>();
        break;
}

Upvotes: 2

foad abdollahi
foad abdollahi

Reputation: 1978

you can combine to super object and check is item is null or not

public class InboundMessageText
{
    public Message Message { get; set; }
}


public class Message
{
    public string Name { get; set; }
    public string From { get; set; }
    public string Id { get; set; }
    public int Timestamp { get; set; }
    public string Type { get; set; }
    public TextMessage Text { get; set; }
    public ImageMessage Image{ get; set; }
}

public class ImageMessage
{
    public string Mime_Type { get; set; }
    public string Link { get; set; }
    public string Caption { get; set; }
}

public class TextMessage
{
    public string Body { get; set; }
}



var inboundMessage = JsonConvert.DeserializeObject <InboundMessageText> ("json string");

if (inboundMessage.Message.Type == "text") { 
//InboundType.Text ;
 }

if (inboundMessage.Message.Type == "image") { 
//  InboundType.Image;
 }

Upvotes: 0

Related Questions