I'm taking in a JSON that I do not control in the format of this sample:
{
"Transaction Information": [
{
"Type": "This is the Type"
},
{
"Action": "No"
},
{
"Owner": "Simpsons"
},
{
"Buyer/Broker": "Y"
},
{
"Compensation to Buyer": 3.0
}
]
}
I want to deserialize it to a class such as:
public class Transaction
{
[JsonProperty("Transaction Information")]
public TransactionInformation[] TransactionInformation { get; set; }
}
public partial class TransactionInformation
{
[JsonProperty("Type", NullValueHandling = NullValueHandling.Ignore)]
public string Type { get; set; }
[JsonProperty("Action", NullValueHandling = NullValueHandling.Ignore)]
public string Action { get; set; }
[JsonProperty("Owner", NullValueHandling = NullValueHandling.Ignore)]
public string Owner { get; set; }
[JsonProperty("Buyer/Broker", NullValueHandling = NullValueHandling.Ignore)]
public string BuyerBroker { get; set; }
[JsonProperty("Compensation to Buyer", NullValueHandling = NullValueHandling.Ignore)]
public long? CompensationToBuyer { get; set; }
}
using the code
var obj = JsonConvert.DeserializeObject<Transaction>(json);
However that gives me a Transaction.TransactionInformation object with 5 records each with all 5 elements with each record having all null values except for one of the 5 elements.
Is there a simple way to to return all 5 elements in one record?
Is there a simple way to to return all 5 elements in one record?
Sure -- Just put each property in a single record:
var finalRecord = new TransactionInformation
{
Type = obj.TransactionInformation.FirstOrDefault(x => !string.IsNullOrEmpty(x.Type))?.Type,
Action = obj.TransactionInformation.FirstOrDefault(x => !string.IsNullOrEmpty(x.Action))?.Action,
Owner = obj.TransactionInformation.FirstOrDefault(x => !string.IsNullOrEmpty(x.Owner))?.Owner,
BuyerBroker = obj.TransactionInformation.FirstOrDefault(x => !string.IsNullOrEmpty(x.BuyerBroker))?.BuyerBroker,
CompensationToBuyer = obj.TransactionInformation.FirstOrDefault(x => x.CompensationToBuyer.HasValue)?.CompensationToBuyer
};
That JSON data you are working with isn't in the most convenient format. In a perfect world it would look like this:
{
"Transaction Information": [{
"Type": "This is the Type",
"Action": "No",
"Owner": "Simpsons",
"Buyer/Broker": "Y",
"Compensation to Buyer": 3.0
}
]
}
Then what you were doing would have worked fine and you wouldn't have to do this last step to normalize the data.
You can create a custom JsonConverter that enables you to hook into the deserialization for the type:
public class TransactionConverter : JsonConverter<Transaction>
{
public override void WriteJson(JsonWriter writer, Transaction value, JsonSerializer serializer)
{
}
public override Transaction ReadJson(JsonReader reader, Type objectType, Transaction existingValue,
bool hasExistingValue, JsonSerializer serializer)
{
var rootChildren = JToken.ReadFrom(reader).First.Children();
var item = new TransactionInformation();
foreach (var child in rootChildren.Children())
{
item.Type ??= (string)child["Type"];
item.Action ??= (string) child["Action"];
item.BuyerBroker ??= (string)child["Buyer/Broker"];
item.Owner ??= (string)child["Owner"];
item.CompensationToBuyer ??= (long?)child["Compensation to Buyer"];
}
return new Transaction {TransactionInformation = new[] {item}};
}
public override bool CanRead => true;
}
and then call it:
var tx = JsonConvert.DeserializeObject<Transaction>(str, new TransactionConverter());
Related
Sorry for my poor English.
I had success run code from this doc. I got new JSON data and there is another problem.
The JSON data is defined like this:
{
"id": 3,
"title": "aaa",
"typeDiscriminator": "search",
"settingDataTemp": {
"id": 11,
"type": "11",
"value": "11"
}
}
And the POCO class is defined as:
public class RootContent
{
public int id { get; set; }
public string title { get; set; }
public PageModuleType typeDiscriminator { get; set; }
public IPageSubContentSetting settingDataTemp { get; set; }
}
I want to deserialize settingDataTemp object, so the JsonConverter Read method like
public override IPageSubContentSetting Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
PageModuleType typeDiscriminator;
string rawText;
var discriminatorPropName = nameof(RootContent.typeDiscriminator);
using (var jsonDocument = JsonDocument.ParseValue(ref reader))
{
if (!jsonDocument.RootElement.TryGetProperty(discriminatorPropName, out var typeProperty))
{
throw new JsonException();
}
var result = Enum.TryParse(typeProperty.GetString(), true, out typeDiscriminator);
if (!result)
{
throw new JsonException();
}
rawText = jsonDocument.RootElement.GetRawText();
}
}
Can't get typeDiscriminator from JsonDocument.RootElement because it's defined on outer object.
Is there any way to get typeDiscriminator value?
I solved problem just use NewtonSoft.Json To edit JSON struct and copy typeDiscriminator value from root to settingDataTemp element.
I have to deserialize a response from an api which has the following structure:
[
{
"starttime": "...",
"endtime": "....",
"var1": {},
"var2": {}
},
{
"starttime": "...",
"endtime": "....",
"var1": {},
"var3": {}
},
{
"starttime": "...",
"endtime": "....",
"var1": {}
}
]
Some insights:
The JSON is an array of objects
Every object inside the array will ALWAYS have the properties "starttime" and "endtime"
Objects "var1", "var2", "var3" will ALWAYS have the same properties inside them... but the problem is that the object keys (var1, var2 or var3) are dynamic. It can be any string, and also the amount of this kind of objects is dynamic (I could have 3, or zero "var" objects).
I was thinking something like this, to deserialize the JSON string into a List of objects with properties "starttime", "endtime" and a dictionary with all the "var" objects.
public class MyResponse
{
[JsonProperty(PropertyName = "starttime")]
public string StartTime { get; set; }
[JsonProperty(PropertyName = "endtime")]
public string EndTime { get; set; }
public Dictionary<string, VarObject> VarData { get; set; }
}
But the VarData property is always null.
Has anyone tried something like this?
You have two options, the first is to deserialise directly to a List<Dictionary<string, object>>, for example:
var responses = JsonConvert.DeserializeObject<List<Dictionary<string, object>>>(json);
Alternatively, if you are stuck on using your object, you will need to write a custom converter. For example, something like this:
public class MyResponseConverter : JsonConverter
{
public override bool CanConvert(Type type) => type == typeof(MyResponse);
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var responseObject = JObject.Load(reader);
MyResponse response = new MyResponse
{
StartTime = (string)responseObject["starttime"],
EndTime = (string)responseObject["endtime"],
};
var varData = new Dictionary<string, object>();
foreach (var property in responseObject.Properties())
{
if(property.Name == "starttime" || property.Name == "endtime")
{
continue;
}
varData.Add(property.Name, property.Value);
}
response.VarData = varData;
return response;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
// If you want to write to JSON, you will need to implement this method
throw new NotImplementedException();
}
}
And your class would change slightly to this:
[JsonConverter(typeof(MyResponseConverter))]
public class MyResponse
{
[JsonProperty(PropertyName = "starttime")]
public string StartTime { get; set; }
[JsonProperty(PropertyName = "endtime")]
public string EndTime { get; set; }
public Dictionary<string, object> VarData { get; set; }
}
Now you deserialise like this:
var responses = JsonConvert.DeserializeObject<List<MyResponse>>(json);
You can view example Here https://dotnetfiddle.net/QgXWQi.
But for more flexibility, this logic is better to implement in method that marked as [OnDeserialized]
Like here https://www.newtonsoft.com/json/help/html/SerializationAttributes.htm
The main idea is to parse it as JObject and then convert to Dictionary
var jObj = JObject.Parse(jsonText);
var varData = jObj
.Children<JProperty>()
.Where(p => p.Name != "starttime" && p.Name != "endtime")
.ToDictionary(x=> x.Name, x => ((JObject)x.Value).ToObject<VarObject>());
I have two classes, namely Roles and Module in Module class I have two properties Name,Permission.
for now, just testing purpose I'm creating one demo code.
Class file
public class Roles
{
public Module[] modules { get; set; }
public Roles()
{
modules = new Module[] { };
}
}
public class Module
{
public string Name { get; set; }
public string[] Permission { get; set; }
}
Controller code
public ActionResult Index()
{
var oRoles = new Roles();
oRoles.modules = new Module[] {
new Module(){
Name="Page-Profile",
Permission=new string[]{ "Edit","View","Delete"}
},
new Module(){
Name="User",
Permission=new string[]{ "Edit","View","Delete","Update"}
}
};
var json = Newtonsoft.Json.JsonConvert.SerializeObject(oRoles);
return View(json);
}
It's working fine I'm getting result also but I want result like this.
Expected result.
{
"modules": [
{
"Page-Profile": [
"Edit",
"View",
"Delete"
]
},
{
"User": [
"Edit",
"View",
"Update",
"Delete"
]
}
]
}
Currently I'm getting a result like this. is there any way to modify JSON remove all key and get only values.
{
"modules": [
{
"Name": "Page-Profile",
"Permission": [
"Edit",
"View",
"Delete"
]
},
{
"Name": "User",
"Permission": [
"Edit",
"View",
"Delete",
"Update"
]
}
]
}
Note: How to remove key properties i want only name value and in name value again i wan't all permission as mention in excpected result.
Its working for me ,try this :
Code
public class Roles
{
public Roles()
{
modules = new List<Dictionary<string, List<string>>>();
}
public List<Dictionary<string, List<string>>> modules { get; set; }
}
/*Index*/
public ActionResult Index()
{
var oRoles = new Roles();
var userRolePermissionsAndModulesList = userRolePermissionManager.GetAllUserRolePermissionsAndModules(userId);
foreach (var module in userRolePermissionsAndModulesList)
{
var objPermissionWithModules = new Dictionary<string, List<string>>();
var permission = new List<string> { };
if (module.CanCreate)
permission.Add("Create");
if (module.CanDelete)
permission.Add("Delete");
if (module.CanEdit)
permission.Add("Update");
if (module.CanView)
permission.Add("View");
objPermissionWithModules.Add(module.ModuleName, permission);
oRoles.modules.Add(objPermissionWithModules);
}
var json = Newtonsoft.Json.JsonConvert.SerializeObject(oRoles);
return View(json);
}
Please compare your output :
{
"modules":[
{
"Page-Profile":[
"Edit",
"View",
"Delete"
]
},
{
"user":[
"Edit",
"View",
"Delete",
"Update"
]
}
]
}
Remove Module class and try changing Roles as follows to get expected json format:
public class Roles
{
public Roles()
{
modules = new Dictionary<string, List<string>>();
}
public Dictionary<string, List<string>> modules { get; set; }
}
Controller Action code:
public ActionResult Index()
{
var oRoles = new Roles();
oRoles.modules.Add("Page-Profile", new List<string>{"Edit","View","Delete"});
oRoles.modules.Add("user", new List<string>{"Edit","View","Delete","Update"});
// Not sure why you are serializing to json.
// you can directly return View(oRoles) or PartialView(oRoles)
var json = Newtonsoft.Json.JsonConvert.SerializeObject(oRoles);
return View(json);
}
There are two way to achieve it
By writing the custom converter
By changing the Roles object
By writing the custom converter
You can implement the CustomJsonConverter as follows which convert the name to key and permission to value:
public class FlatternKeysConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
Module o = (Module)value;
JObject newObject = new JObject(new JProperty(o.Name, o.Permission));
newObject.WriteTo(writer);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException("Unnecessary because CanRead is false. The type will skip the converter.");
}
public override bool CanRead
{
get { return false; }
}
public override bool CanConvert(Type objectType)
{
return true;
}
}
And attach the JsonConverter as
[JsonConverter(typeof(FlatternKeysConverter))]
public class Module
{
public string Name { get; set; }
public string[] Permission { get; set; }
}
The generated JSON will be as follows :
{"modules":[{"Page-Profile":["Edit","View","Delete"]},{"User":["Edit","View","Delete","Update"]}]}
By changing the Roles object
Change the roles object to dictionary
public class Role
{
public class Roles
{
public Dictionary<string, List<string>> Modules {get; set;}
}
}
You can check the https://dotnetfiddle.net/Hs3i04 dotnet fiddle which shows both approaches.
In C #, I have 5-6 days and I wanted to try to use the api one site.
I have deserialize JSON and here is the format
[
{
"uid": 1476402,
"first_name": "",
"last_name": "",
"domain": "sandrische",
"online": 1,
"user_id": 1476402
},
{
"uid": 3813182,
"first_name": "",
"last_name": "",
"domain": "id3813182",
"online": 0,
"user_id": 3813182
},
{
"uid": 12789624,
"first_name": "",
"last_name": "",
"domain": "id12789624",
"online": 0,
"user_id": 12789624
}]
there is a class
public class vkResponse
{
[JsonProperty(PropertyName = "uid")]
public int Id { get; set; }
[JsonProperty(PropertyName = "first_name")]
public string FirstName { get; set; }
[JsonProperty(PropertyName = "last_name")]
public string LastName { get; set; }
[JsonProperty(PropertyName = "photo_50")]
public Uri PhotoUri { get; set; }
[JsonProperty(PropertyName = "online")]
[JsonConverter(typeof(BoolConverter))]
public bool IsOnline { get; set; }
[JsonProperty(PropertyName = "lists")]
public List<int> Lists { get; set; }
}
public class BoolConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteValue(((bool)value) ? 1 : 0);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return reader.Value.ToString() == "1";
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(bool);
}
}
I want to get id
var req = new HttpRequest();
string resp = req.Get("https://api.vk.com/method/friends.get?user_ids=1&fields=domain&access_token=" + GetToken()).ToString();
JObject o = JObject.Parse(resp);
JArray array = (JArray)o["response"];
vkResponse v = JsonConvert.DeserializeObject<vkResponse>(array.First().ToString());
richTextBox1.Text = v.Id.ToString();
But I get only the first ID, how to get all ID?
I think that the problem in this array.First().ToString() ? Please help or give an example.
var v = JsonConvert.DeserializeObject<IEnumerable<vkResponse>>(array.ToString());
var userids = v.Select(x=>x.id);
Your response is an array of vkResponse classes, so you could deserialize it as a c# array:
vkResponse[] vkResponses = JsonConvert.DeserializeObject<vkResponse[]>(array.ToString());
Once you have the array you can loop through and access the IDs of each element.
Pleaase , give me example how loop through and access the IDs of each elemen
OK, here's a way to do it using elementary c# looping constructs and arrays:
vkResponse[] vkResponses = JsonConvert.DeserializeObject<vkResponse[]>(array.ToString());
if (vkResponses == null)
throw new JsonException();
int [] ids = new int[vkResponses.Length];
for (int i = 0; i < vkResponses.Length; i++)
{
ids[i] = vkResponses[i].Id;
}
If you want to show the IDs as a comma-separated sequence of integers in the rich text box, you use the following method to generate the string:
public static string ExtractVkResponseIds(string vkResponseJson)
{
vkResponse[] vkResponses = JsonConvert.DeserializeObject<vkResponse[]>(vkResponseJson);
if (vkResponses == null)
throw new JsonException();
StringBuilder sb = new StringBuilder();
// Format the ids as a comma separated string.
foreach (var response in vkResponses)
{
if (sb.Length > 0)
sb.Append(System.Globalization.CultureInfo.CurrentCulture.TextInfo.ListSeparator);
sb.Append(response.Id.ToString());
}
return sb.ToString();
}
and call it like:
var req = new HttpRequest();
string resp = req.Get("https://api.vk.com/method/friends.get?user_ids=1&fields=domain&access_token=" + GetToken()).ToString();
JObject o = JObject.Parse(resp);
JArray array = (JArray)o["response"];
string ids = ExtractVkResponseIds(array.ToString());
richTextBox1.Text = ids;
I used the localized ListSeparator, by the way, which might not be a comma in your language. You can change it to a literal comma if you want.
Your sample Json string is missing a closing bracket ("]"), by the way.
I have a situation where the JSON returned from a REST-service returns a list of Movie-objects, all specced out with a ton of information. A couple of fields in that REST-service result changes depending on the information available.
An example: A Movie always has some screen captures (images), actors and directors. Depending on the movie in question, there might be one or more images, one or more actors and one or more directors. Sample JSON for a couple of cases:
{
"title": "Movie title",
"images": [
"http://www.url.com/img_0.jpg",
"http://www.url.com/img_1.jpg",
"http://www.url.com/img_2.jpg",
"http://www.url.com/img_3.jpg",
"http://www.url.com/img_4.jpg"
],
"actors": [
"Steven Berkoff",
"Nikolaj Coster-Waldau",
"Julie Cox"
],
"directors": "Simon Aeby"
},
{
"title": "Another movie",
"images": "http://www.url.com/img_1.jpg",
"actors": "actor 1"
"directors": [
"Justin Bieber",
"Justin Timberlake"
]
}
The question is, using JSON.net, how can I create a converter that deals with this problem? I've been scouring the internet, but still haven't found a solution.
Another spin on the same question: If a field is either a List of strings or a simple string, how do I make JSON.NET create a List either way (and if just a simple string, create a list with one member)
EDIT: This REST-service is out of my control
Ok, I did it for fun, but don't think is useful or the best way, anyway...
Declaring the "dynamic" attributes as object and then create methods to obtain the properties as something like ImagesAsList or ImagesAsString. I did it with Extension Methods.....
var movies = JsonConvert.DeserializeObject<List<Movie>>(str);
Class
class Movie
{
[JsonProperty("title")]
public string Title { get; set; }
[JsonProperty("images")]
public object Images { get; set; }
[JsonProperty("actors")]
public object Actor { get; set; }
[JsonProperty("directors")]
public object Directors { get; set; }
}
Extension Methods
static class MovieExtension
{
public static List<string> ImagesAsList(this Movie m)
{
var jArray = (m.Images as JArray);
if (jArray == null) return null;
return jArray.Select(x => x.ToString()).ToList();
}
public static string ImagesAsString(this Movie m)
{
return m.Images as string;
}
}
EDIT
After reading #yamen comments I did some changes like:
var settings = new JsonSerializerSettings();
settings.Converters.Add(new MoviesConverter());
var movies = JsonConvert.DeserializeObject<List<Movie>>(str, settings);
Class
class Movie
{
[JsonProperty("title")]
public List<string> Title { get; set; }
[JsonProperty("images")]
public List<string> Images { get; set; }
[JsonProperty("actors")]
public List<string> Actor { get; set; }
[JsonProperty("directors")]
public List<string> Directors { get; set; }
}
Converter
class MoviesConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(string)) || (objectType == typeof(List<string>)) ;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.StartArray)
{
var l = new List<string>();
reader.Read();
while (reader.TokenType != JsonToken.EndArray)
{
l.Add(reader.Value as string);
reader.Read();
}
return l;
}
else
{
return new List<string> { reader.Value as string };
}
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
//ToDo here we can decide to write the json as
//if only has one attribute output as string if it has more output as list
}
}
You won't be able to serialise directly to an object, but you can do so manually without too much effort. JSON.Net contains LINQ to JSON. First define a method that will always return a list of type T even if the underlying JSON is not an array:
public List<T> getSingleOrArray<T>(JToken token)
{
if (token.HasValues)
{
return token.Select(m => m.ToObject<T>()).ToList();
}
else
{
return new List<T> { token.ToObject<T>() };
}
}
Sample usage:
JObject m1 = JObject.Parse(#"{
""title"": ""Movie title"",
""images"": [
""http://www.url.com/img_0.jpg"",
""http://www.url.com/img_1.jpg""
],
""actors"": [
""Steven Berkoff"",
""Julie Cox""
],
""directors"": ""Simon Aeby""
}");
JObject m2 = JObject.Parse(#"{
""title"": ""Another movie"",
""images"": ""http://www.url.com/img_1.jpg"",
""actors"": ""actor 1"",
""directors"": [
""Justin Bieber"",
""Justin Timberlake""
]
}");
IList<String> m1_directors = getSingleOrArray<string>(m1["directors"]);
IList<String> m2_directors = getSingleOrArray<string>(m2["directors"]);
m1_directory is a list with a single element, m2_directors is a list with two elements.