How can I deseralize this JSON to C# collection with Json.NET ?
{
"3396": [{
"id": 767570,
"t": {
"0-43": [{
"id": 71968108,
"n": "No",
"v": 1.55,
"bt": 1
}, {
Create a model in C#:
public class YourModelJSON
{
[JsonProperty("yourmodel")]
public YourModel YourModel { get; set; }
}
public class YourModel
{
[JsonProperty("id")]
public string myId{ get; set; }
[JsonProperty("t")]
public string myT { get; set; }
...
}
And then deserialize your json with:
JsonConvert.DeserializeObject<List<YourModelJson>>(json);
I think you will have a hard time putting this json into classes, so I'd go for the dynamic solution here:
dynamic result = JsonConvert.DeserializeObject(json); // json -> escaped string
var array3396 = result["3396"];
var arrayT = array3396[0]["t"];
var array043 = arrayT["0-43"][0];
var id = array043["id"]; // output: 71968108
Made it as follows:
dynamic data = h.GetDynamicJSON(urlDet);
if (data != null)
{
foreach (var d in data)
{
var json = JsonConvert.SerializeObject(d.Value);
var obj = JsonConvert.DeserializeObject<List<Details>>(json);
}
}
Got source as dynamic object, then serialized 'dynamic named' value, and deserialized it to strong type object.
Related
My AppConfig.json:
{
"MyTimeZone: "CET",
"RegularString" : "SomeValue",
"AnArray" : ["1","2"]
}
My POCO class:
public class Settings
{
public TimeZoneInfo MyTimeZone { get; set; }
public string RegularString { get; set; }
public IList<string> AnArray { get; set; }
}
Registry.cs:
var configuration = GetConfiguration("AppSettings.json");
services.Configure<Settings>(configuration.GetSection("Settings"));
This of course does not bind "CET" into a valid TimeZoneInfo object. Now the question is what is the best place in my application (a web app) to convert from string to TimeZoneInfo? Is there a way to automatically convert string config values to objects based on certain rules without creating custom converters?
Reference Use DI services to configure options
services.AddOptions<Settings>()
.Configure<IConfiguration>((setting, configuration) => {
var section = config.GetSection("Settings");
//This will populate the other properties that can bind by default
section.Bind(setting);
//this will extract the remaining value and set it mnually
string value = section.GetValue<string>("MyTimeZone");
TimeZoneInfo info = TimeZoneInfo.FindSystemTimeZoneById(value);
setting.MyTimeZone = info;
});
The complex setting value can be extracted directly from configuration via DI and used to create the time zone and apply it to the settings.
It just my personal opinion but I prefer the MyTimeZone to be a json object instead only a string. Consider the following:
"Settings": {
"MyTimeZone": {
"ConfigureTimeZoneById": "CET"
},
"RegularString": "SomeValue",
"AnArray": [ "1", "2" ]
}
MyTimeZone.ConfigureTimeZoneById is not part of the actual data object. It's just proxy to bind object to configuration. This how TimeZone class might look like:
public class TimeZone
{
private string configureTimeZoneById { get; set; }
public string ConfigureTimeZoneById
{
get { return configureTimeZoneById; }
set
{
configureTimeZoneById = value;
InitializeTimeZone(value);
}
}
public string TimeZoneId { get; set; }
public string OtherProperties { get; set; }
private void InitializeTimeZone(string id)
{
var getTimeZone = TimeZonesDataset().FirstOrDefault(tzon => tzon.TimeZoneId.Equals(id));
if (getTimeZone != null)
{
this.TimeZoneId = getTimeZone.TimeZoneId;
this.OtherProperties = getTimeZone.OtherProperties;
}
}
//dummy dataset
private List<TimeZone> TimeZonesDataset() => new List<TimeZone> {
new TimeZone{TimeZoneId = "CET", OtherProperties = "Dummy properties to prove point"},
new TimeZone{TimeZoneId = "GMT", OtherProperties = default},
};
I have a database table named "application" in my postgresql database.
id name settings
----------------------------------------------------------------
1 x "{"color":"red", "left":"30px"}"
2 y "{"menuSize":"4", "menuOrientation":"horizontal"}"
my settings columnn has text type that includes json data as text format.
I am using this data in my asp.net web api application. The wab api can convert an object to a json data.
public class AppController : ApiController
{
App[] apps = new App[]
{
new App { Id = 1, Name = "x" },
new App { Id = 2, Name = "y" }
};
public IEnumerable<App> GetApps()
{
return apps;
}
}
But my model includes a string property that has a json formatted data.
public class AppController : ApiController
{
App[] apps = new App[]
{
new App { Id = 1, Name = "x", Settings = "{\"color\":\"red\", \"left\":\"30px\"}" }
};
public IEnumerable<App> GetApps()
{
return apps;
}
}
I want to get a json response like following:
[
{
id: 1,
name: "x",
color: "color",
left: "30px"
}
]
all columns are converted to a json format.
Use Newtonsoft library to parse json and then add new properties
public HttpResponseMessage GetApps()
JObject jsonObject = JObject.Parse("{\"color\":\"red\", \"left\":\"30px\"}");
jsonObject.Add("id", 1);
jsonObject.Add("name", x);
return new HttpResponseMessage {
Content = new StringContent(jsonObject.ToString(Formatting.None), Encoding.UTF8, "application/json"),
};
}
Try to use below code to return IEnumerable<JObject> since your keys in settings is dynamic.
public IEnumerable<JObject> GetApps()
{
var jsonList = new List<JObject>();
App[] apps = new App[]
{
new App { Id = 1, Name = "x", Settings = "{\"color\":\"red\", \"left\":\"30px\"}" },
new App { Id = 2, Name = "y", Settings = "{\"menuSize\":\"4\", \"menuOrientation\":\"horizontal\"}" }
};
foreach(var app in apps)
{
var obj = new JObject();
obj.Add("id", app.Id);
obj.Add("name", app.Name);
JObject settingsJsonObj = JObject.Parse(app.Settings);
foreach (var property in settingsJsonObj.Properties())
{
var name = property.Name;
obj.Add(name, settingsJsonObj.GetValue(name));
}
jsonList.Add(obj);
}
return jsonList;
}
Result:
[
{
"id": 1,
"name": "x",
"color": "red",
"left": "30px"
},
{
"id": 2,
"name": "y",
"menuSize": "4",
"menuOrientation": "horizontal"
}
]
If you use asp.net core 3.0, you need to add a package reference to Microsoft.AspNetCore.Mvc.NewtonsoftJson and update Startup.ConfigureServices to call AddNewtonsoftJson.
services.AddMvc().AddNewtonsoftJson();
Update:
Below is a demo to use custom json converter in asp.net core 3.0 with Newtonsoft.Json;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
public class AppJsonConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteStartObject();
{
writer.WritePropertyName("Id");
writer.WriteValue(value.GetType().GetProperty("Id").GetValue(value).ToString());
writer.WritePropertyName("Name");
writer.WriteValue(value.GetType().GetProperty("Name").GetValue(value).ToString());
var settings = value.GetType().GetProperty("Settings").GetValue(value);
JObject settingsJsonObj = JObject.Parse(settings.ToString());
foreach (var property in settingsJsonObj.Properties())
{
var name = property.Name;
writer.WritePropertyName(name);
writer.WriteValue(settingsJsonObj.GetValue(name));
}
}
writer.WriteEndObject();
}
public override bool CanConvert(Type objectType)
{
throw new NotImplementedException();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
Model:
[JsonConverter(typeof(AppJsonConverter))]
public class App
{
public int Id { get; set; }
public string Name { get; set; }
public string Settings { get; set; }
}
Controller:
//add `using Newtonsoft.Json;`
public IEnumerable<Object> GetApps()
{
App[] apps = new App[]
{
new App { Id = 1, Name = "x", Settings = "{\"color\":\"red\", \"left\":\"30px\"}" },
new App { Id = 2, Name = "y", Settings = "{\"menuSize\":\"4\", \"menuOrientation\":\"horizontal\"}" }
};
var jsonServices = JsonConvert.SerializeObject(apps);
var result = JsonConvert.DeserializeObject<List<Object>>(jsonServices);
return result;
}
In a controller I serialized form data to json and saved to database:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(IFormCollection formData)
{
var json = JsonConvert.SerializeObject(formData);
var doc = new Doc()
{
Subject = formData["subject"],
Content = json
};
_context.Docs.Add(doc);
_context.SaveChanges();
return RedirectToAction("Edit", new { Id = doc.Id });
}
Now, I'd like to deserialize form data and reconstruct the form:
public IActionResult Edit(int id)
{
var doc = _context.Docs
.Where(o => o.Id == id).FirstOrDefault();
if (doc == null)
{
ViewData["ErrorMessage"] = "Not found";
return View("Error");
}
var formData = JsonConvert.DeserializeObject<IFormCollection>(doc.Content);
ViewData["FormData"] = formData;
return View(doc);
}
The above will throw an exception at deserialization:
JsonSerializationException: Cannot create and populate list type Microsoft.AspNetCore.Http.IFormCollection. Path '', line 1, position 1.
If I do not specify type, then deserialization succeeds; but I prefer it
to be deserialized to IFormCollection. What is the proper way to deserialize IFormCollection?
Also, the reason I'm saving json is because, I'm dealing with 30 or so types of forms, and I do not want to create strongly typed model objects for each of them. Any advice is welcome.
The way I used to deal with json object in Database:
In your entity object add an other class to handle mapping with your json object :
public class Contact
{
public int Id { get; set; }
internal string _Data { get; set; }
[NotMapped]
public UserData Data
{
get { return _Data == null ? null : JsonConvert.DeserializeObject<UserData>(_Data); }
set { _Data = JsonConvert.SerializeObject(value); }
}
}
public class UserData
{
public string Name { get; set; }
//Add your json data here
}
And my controller look like
public IActionResult Add(AddContactViewModel model)
{
var contact = new Contact()
{
Data = JsonConvert.DeserializeObject<UserData>(model.Data.ToString())
};
_contactService.Add(contact);
return new OkObjectResult(contact);
}
public class AddContactViewModel
{
public JObject Data { get; set; }
}
Thank's to mapping, when you access the object data contained by the object contact you can access all your data préviously defined in the UserData object (Object names can change in your case)
var contact = new Contact()
{
Data = JsonConvert.DeserializeObject<UserData>(model.Data.ToString())
};
contact.Data.Name;
For the life of me, I can't figure out how to parse the collection of device_tokens out of this using JSON.Net. I can parse out the top level collection fine, but am bombing on parsing out the device tokens in any way shape or form. Anyone have any ideas?
{
"next_page": "https://go.urbanairship.com/api/device_tokens/?start=<MY_TOKEN>&limit=2",
"device_tokens_count": 87,
"device_tokens": [
{
"device_token": "<MY_TOKEN>",
"active": false,
"alias": null,
"tags": []
},
{
"device_token": "<MY_TOKEN>",
"active": true,
"alias": null,
"tags": ["tag1", "tag2"]
}
],
"active_device_tokens_count": 37
}
Heres how you can do it using Json.NET
First create a class to represent a single device_token:
public class DeviceToken
{
public string device_token { get; set; }
public bool active { get; set; }
public object alias { get; set; }
public List<object> tags { get; set; }
}
Then using the JsonConvert class you can deserialize the json device_token array to a list of DeviceToken objects.
string json = "{\"next_page\": \"https://go.urbanairship.com/api/device_tokens/?start=07AAFE44CD82C2F4E3FBAB8962A95B95F90A54857FB8532A155DE3510B481C13&limit=2\",\"device_tokens_count\": 87,\"device_tokens\": [{\"device_token\": \"0101F9929660BAD9FFF31A0B5FA32620FA988507DFFA52BD6C1C1F4783EDA2DB\",\"active\": false,\"alias\": null,\"tags\": []},{\"device_token\": \"07AAFE44CD82C2F4E3FBAB8962A95B95F90A54857FB8532A155DE3510B481C13\",\"active\": true,\"alias\": null,\"tags\": [\"tag1\", \"tag2\"] }],\"active_device_tokens_count\": 37}";
JObject obj = JObject.Parse(json);
var deviceTokens = JsonConvert.DeserializeObject<List<DeviceToken>>(obj["device_tokens"].ToString());
I'm building a JSON only WepApi and I have a controller which returns a list.
I have decorated the list with Datacontract/Datamember attributes like this:
[DataContract(Name = "Files", Namespace = "http://schemas.example.com")]
public class FileDesc
{
[DataMember(Name = "MyFileName")]
public string Name { get; set; }
[DataMember(Name = "MyFilePath")]
public string Path { get; set; }
[DataMember(Name = "MyFileSize")]
public long? Size { get; set; }
public FileDesc(string n, string p, long? s)
{
Name = n;
Path = p;
Size = s;
}
}
In my controller I return the list like this:
// Response
List<FileDesc> FileList = new List<FileDesc>();
foreach (MultipartFileData file in provider.FileData)
{
FileList.Add(new FileDesc(file.Headers.ContentDisposition.FileName, file.LocalFileName , file.Headers.ContentDisposition.Size ));
}
return FileList;
But in the JSON output the Name attribute for the list is missing:
[
{
"myFileName": "\"ArduinoUNO.png\"",
"myFilePath": "c:\\images\\ArduinoUNO.png",
"myFileSize": null
}
]
To force JSON-only output i have removed the xml formatter on Global.asax:
//Only JSON
var formatters = GlobalConfiguration.Configuration.Formatters;
formatters.Remove(formatters.XmlFormatter);
Thanks in advance
Arrays don't have names by themselves in JSON. If you want a name on the list, you need an outer object that has a named property to hold the list.
Something like this:
public class Response
{
[DataMember(Name = "Files")]
List<FileDesc> FileList { get; set; }
}
The JSON would then look like this:
{
"Files":
[
{
"myFileName": "\"ArduinoUNO.png\"",
"myFilePath": "c:\\images\\ArduinoUNO.png",
"myFileSize": null
}
]
}