0

This is my JSON

{
    "type": "user_settings",
    "created_at": 1610973280043,
    "data": {
        "user_id": 12345,
        "updated_at": "2021-01-18T15:34:40+03:00"
    }
}

These are my classes:

public class BaseMessage
{
    [JsonProperty("type")]
    public string Type { get; set; }

    [JsonProperty("created_at")]
    public long CreatedAt { get; set; }

    [JsonProperty("data")]
    public DataDTO Data { get; set; }

    public string DataJson {get; set;} // <-- Here I need string like this "{ "user_id": 12345, "updated_at": "2021-01-18T15:34:40+03:00" }"
}

public class DataDTO
{
    [JsonProperty("user_id")]
    public int UserId { get; set; }

    [JsonProperty("updated_at")]
    public DateTime? UpdatedAt { get; set; }
}

So I need parsed "data" (it works ok) and save nested JSON as a string (I don't know how). Is there elegant way to save nested JSON into string property?

Something like this:

public class BaseMessage
{
    [JsonProperty("type")]
    public string Type { get; set; }

    [JsonProperty("created_at")]
    public long CreatedAt { get; set; }

    [JsonProperty("data")]
    public DataDTO Data { get; set; }

    [JsonPropertyAsString("data")] // <-- This is my fantasy :)
    public string DataJson {get; set; }
}
Phil
  • 82
  • 8
  • 1
    You must add a [`JsonConverter`](https://www.newtonsoft.com/json/help/html/CustomJsonConverter.htm) for `DataJson`. In fact this looks like a duplicate of [How can I serialize and deserialize a type with a string member that contains “raw” JSON, without escaping the JSON in the process](https://stackoverflow.com/q/40529125/3744182) and [Efficiently get full json string in JsonConverter.ReadJson()](https://stackoverflow.com/q/56944160/3744182), agree? – dbc Jan 20 '21 at 22:37
  • Do you really need a string? What about a parsed JObject? – Jeremy Lakeman Jan 20 '21 at 23:57
  • Oh I see what you are trying to do -- you are trying to bind the JSON to *two properties at once* -- one a JSON string and the other the deserialized DataDTO. There's nothing built in for that. Suggest to use a surrogate property for one of them, as was suggested in the [deleted answer](https://stackoverflow.com/a/65819006/3744182) of [E. Shcherbo](https://stackoverflow.com/users/8715436/e-shcherbo). – dbc Jan 21 '21 at 00:47
  • @dbc Yes, this is what I was looking for. These links very helpful. Thank you very much! – Phil Jan 22 '21 at 15:16

2 Answers2

2

As @dbc commented you can create a custom JsonConverter for the DataJson property, but you also should do something with your another property which is mapped from the data JSON field - Data of DataDTO type. I can propose the following solution:

1. Custom JSON Converter (I took this from @dbc's answer)

public class RawConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        throw new NotImplementedException();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
       if (reader.TokenType == JsonToken.Null)
          return null;
       var raw = JRaw.Create(reader);
       return raw.ToString();
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
       var s = (string)value;
       writer.WriteRawValue(s);
     }
}

2. Decorate your DataJson property with the JsonConverter attribute and remove JsonPropertyAttribute for the Data property

Note that if you don't remove the JsonPropertyAttribute then it won't work, since you have two properties which are mapped from the same JSON field, and as I know this is not supported by Json.NET by default.

public class BaseMessage
{
   [JsonProperty("type")]
   public string Type { get; set; }

   [JsonProperty("created_at")]
   public long CreatedAt { get; set; }

   public DataDTO Data { get; set; }

   [JsonProperty("data")]
   [JsonConverter(typeof(RawConverter))]
   public string DataJson {get; set;}
}

3. Update your BaseMessage class so this calculates the value of the Data property from DataJson

public class BaseMessage
{
   private DataDTO data;

   [JsonProperty("type")]
   public string Type { get; set; }

   [JsonProperty("created_at")]
   public long CreatedAt { get; set; }

   public DataDTO Data
   {
       if (data == null)
       {
          data = JsonConvert.DeserializeObject<DataDTO>(DataJson);
       }
       return data;
   }

   [JsonProperty("data")]
   [JsonConverter(typeof(RawConverter))]
   public string DataJson {get; set;}
}

Note that I believe this is not the best solution and sure that there are other much better alternatives, but it might be feasible in your case.

E. Shcherbo
  • 1,128
  • 8
  • 15
0

Do you mean to use this ??

var data = Newtonsoft.Json.JsonConvert.SerializeObject(object);

if yes, install the newtonSoft packge.

RamyRahman
  • 76
  • 7