I have json like this
{
"guid": "b1e3c29f-066f-417b-b6b6-795ffae90f0a",
"status": "complete",
"type": "colors",
"results": {
"events": [
{
"title": "event1",
"other": {
"Red": "red",
"Green": "green",
"Blue": "blue"
}
},
{
"title": "event2",
"other": {
"Yelow": "yellow",
"Orange": "orange"
}
}
]
}
}
and classes for deserialization looks like this
public class Other
{
public string Red { get; set; }
public string Green { get; set; }
public string Blue { get; set; }
public string Yelow { get; set; }
public string Orange { get; set; }
}
public class Event
{
public string title { get; set; }
public Other other { get; set; }
}
public class Results
{
public List<Event> events { get; set; }
}
public class Root
{
public string guid { get; set; }
public string status { get; set; }
public string type { get; set; }
public Results results { get; set; }
}
When I deserialize this json with
var root = JsonConvert.DeserializeObject<Root>(JsonContent);
everything works fine.
The problem is that the content of json section "Other"
is changeable and I don't know its complete content.
Also I need to put this classes in database.
Is there a way to deserialize json section "Other"
as one string field with raw text, and to look something like this:
public class Other
{
public string AllFieldsFromOtherSectionAsRawText { get; set; }
}
CodePudding user response:
If you define your Other
class like this:
public class Other
{
public Other(string rawData)
{
Content = rawData;
}
public string Content { get; }
}
Then you can write a custom JsonConverter
, which will treat your other
nodes as string
:
class ObjectToStringJsonConverter : JsonConverter
{
private readonly Type theType;
public ObjectToStringJsonConverter(Type type) => theType = type;
public override bool CanConvert(Type objectType) => objectType == theType;
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
=> throw new NotImplementedException();
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JToken token = JToken.Load(reader);
if (token.Type == JTokenType.Object)
{
return Activator.CreateInstance(theType, args: token.ToString());
}
throw new NotSupportedException("The related node is not object");
}
}
The only trick here is this line:
Activator.CreateInstance(theType, args: token.ToString());
- Here we create a new
Other
instance and pass the string representation of theother
node to the constructor.
Then the usage would look like this:
var root = JsonConvert.DeserializeObject<Root>(json, new[] { new ObjectToStringJsonConverter(typeof(Other)) });
CodePudding user response:
Isnt Other a Dictionary represenation?
Can't you write it as Dictionary
public Dictionary<String,String> other { get; set; }
Example:
[Newtonsoft.Json.JsonExtensionData]
public System.Collections.Generic.IDictionary<string, string> other
According to the documentation, you DeserializeObject on type Dictionary:
JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
https://www.newtonsoft.com/json/help/html/DeserializeDictionary.htm
CodePudding user response:
Remove class Other from your code, and fix Event class
public class Event
{
public string title { get; set; }
[JsonProperty(PropertyName = "other")]
public Dictionary<string, string> otherDict { get; set; }
[Newtonsoft.Json.JsonIgnore]
public IEnumerable<string> Other
{
get { return otherDict.Values.ToArray(); }
}
[Newtonsoft.Json.JsonIgnore]
public string AllFieldsFromOtherSectionAsRawText
{
get { return string.Join(",", Other); }
}
}
output
{
"guid": "b1e3c29f-066f-417b-b6b6-795ffae90f0a",
"status": "complete",
"type": "colors",
"results": {
"events": [
{
"title": "event1",
"other": {
"Red": "red",
"Green": "green",
"Blue": "blue"
},
"AllFieldsFromOtherSectionAsRawText": "red,green,blue"
},
{
"title": "event2",
"other": {
"Yelow": "yellow",
"Orange": "orange"
},
"AllFieldsFromOtherSectionAsRawText": "yellow,orange"
}
]
}
}