I have a Json file that was deserialized from a Json Api-Call, now I have to use this file as an object in the main program.
Here is a small section of it:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace Api1
{
public class EcmSimpleField
{
public string value { get; set; }
public string displayName { get; set; }
public string internalName { get; set; }
public string dbName { get; set; }
public bool visible { get; set; }
public string type { get; set; }
}
public class BaseParameter
{
public string value { get; set; }
public string type { get; set; }
}
public class SystemField
{
public string value { get; set; }
public string type { get; set; }
}
How can I use this file as an object in the main program and work with it?
Create a class for the json like you shared above and use deserialise it using Newtonsoft.json dll or any other library.
var obj = JsonConvert.DeserializeObject<YourClass>(jsonString);
This thread will probably help you:
How can I parse JSON with C#?
If your JSON file has changing parameters then the parameters will need to be retrieved in arrays because the array index will always be the same even if the "parameter" changes.
All,
Edit: Firstly thanks for everyone's help. Secondly I'm new to Stack Overflow so apologises if I've added this edit incorrectly.
Following the commments and replies I've updated my class structure to:
services class:
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.Json;
namespace RTT_API
{
class services
{
public List<service> service = new List<service>();
public services()
{
}
}
}
Service class:
using System;
using System.Collections.Generic;
using System.Text;
namespace RTT_API
{
class service
{
public string atocCode{get; set;}
public service()
{
}
}
}
Unfortunately I'm still getting the same error. I think I still haven't quite matched my class structure to the JSON structure? Unfortunately I'm not sure where my mistake is. If it helps to highlight my mistake using a comparison then the following works:
Location class
using System;
using System.Collections.Generic;
using System.Text;
namespace RTT_API
{
class location
{
public string name { get; set; }
public string crs { get; set; }
public location()
{
}
}
}
Location deserilisation command and test output:
location locations = JsonSerializer.Deserialize<location>(channelResponse.RootElement.GetProperty("location").GetRawText());
MessageBox.Show(locations.crs);
Original question:
My JSON is as follows:
{
"location": {
"name": "Bournemouth",
"crs": "BMH",
"tiploc": "BOMO"
},
"filter": null,
"services": [
{
"locationDetail": {
"realtimeActivated": true,
"tiploc": "BOMO",
"crs": "BMH",
"description": "Bournemouth",
"wttBookedArrival": "011630",
"wttBookedDeparture": "011830",
"gbttBookedArrival": "0117",
"gbttBookedDeparture": "0118",
"origin": [
{
"tiploc": "WATRLMN",
"description": "London Waterloo",
"workingTime": "230500",
"publicTime": "2305"
}
],
"destination": [
{
"tiploc": "POOLE",
"description": "Poole",
"workingTime": "013000",
"publicTime": "0130"
}
],
"isCall": true,
"isPublicCall": true,
"realtimeArrival": "0114",
"realtimeArrivalActual": false,
"realtimeDeparture": "0118",
"realtimeDepartureActual": false,
"platform": "3",
"platformConfirmed": false,
"platformChanged": false,
"displayAs": "CALL"
},
"serviceUid": "W90091",
"runDate": "2013-06-11",
"trainIdentity": "1B77",
"runningIdentity": "1B77",
"atocCode": "SW",
"atocName": "South West Trains",
"serviceType": "train",
"isPassenger": true
}
]
}
My class structure is as follows:
servicelist class:
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.Json;
namespace RTT_API
{
class servicelist
{
public List<services> service = new List<services>();
public servicelist()
{
}
}
}
services class:
using System;
using System.Collections.Generic;
using System.Text;
namespace RTT_API
{
class services
{
public int serviceUid;
public services()
{
}
}
}
For deserialisation I have tried:
services servicelist = JsonSerializer.Deserialize<services>(channelResponse.RootElement.GetProperty("services").GetRawText());
and
servicelist servicelist = JsonSerializer.Deserialize<servicelist>(channelResponse.RootElement.GetProperty("services").GetRawText());;
In both cases I get 'System.Text.Json.JsonException'
I think there is a mismatch betwee the class structure and the JSON but I can't work what the problem is? It's the first time I've tried to desarialise an array.
Thanks
using System;
using System.Collections.Generic;
using System.Text;
namespace RTT_API
{
class location
{
public string name { get; set; }
public string crs { get; set; }
public location()
{
}
}
}
You can generate exact C# classes according to your JSON using tools for exactly that purpose. I used https://json2csharp.com/ , another is https://jsonutils.com/ - these are web services and don't require installation on computer, another option is generating classes through Visual Studio (with Web Essentials installed), there you would use Edit - Paste special - paste JSON as class.
Once you have the valid classes (I pasted generated classes below) you can deserialize entire Root object and then access any part of it, including services part:
// jsonInputText holds entire JSON string you posted
Root root = JsonSerializer.Deserialize<Root>(jsonInputText);
List<Service> serviceList = root.services;
Generated classes:
public class Location
{
public string name { get; set; }
public string crs { get; set; }
public string tiploc { get; set; }
}
public class Origin
{
public string tiploc { get; set; }
public string description { get; set; }
public string workingTime { get; set; }
public string publicTime { get; set; }
}
public class Destination
{
public string tiploc { get; set; }
public string description { get; set; }
public string workingTime { get; set; }
public string publicTime { get; set; }
}
public class LocationDetail
{
public bool realtimeActivated { get; set; }
public string tiploc { get; set; }
public string crs { get; set; }
public string description { get; set; }
public string wttBookedArrival { get; set; }
public string wttBookedDeparture { get; set; }
public string gbttBookedArrival { get; set; }
public string gbttBookedDeparture { get; set; }
public List<Origin> origin { get; set; }
public List<Destination> destination { get; set; }
public bool isCall { get; set; }
public bool isPublicCall { get; set; }
public string realtimeArrival { get; set; }
public bool realtimeArrivalActual { get; set; }
public string realtimeDeparture { get; set; }
public bool realtimeDepartureActual { get; set; }
public string platform { get; set; }
public bool platformConfirmed { get; set; }
public bool platformChanged { get; set; }
public string displayAs { get; set; }
}
public class Service
{
public LocationDetail locationDetail { get; set; }
public string serviceUid { get; set; }
public string runDate { get; set; }
public string trainIdentity { get; set; }
public string runningIdentity { get; set; }
public string atocCode { get; set; }
public string atocName { get; set; }
public string serviceType { get; set; }
public bool isPassenger { get; set; }
}
public class Root
{
public Location location { get; set; }
public object filter { get; set; }
public List<Service> services { get; set; }
}
If you need to deserialize only just a part of your json then you can use the JObject and JToken helper classes for that.
var json = File.ReadAllText("Sample.json");
JObject topLevelObject = JObject.Parse(json);
JToken servicesToken = topLevelObject["services"];
var services = servicesToken.ToObject<List<Service>>();
The topLevelObject contains the whole json in a semi-parsed format.
You can use the indexer operator to retrieve an object / array by using one of the top level keys.
On a JToken you can call the ToObject<T> to deserialize the data into a custom data class.
In order to be able to parse your json I had to adjust the services type because the W90091 as serviceUid can't be parsed as int. So here is my Service class definition:
public class Service
{
public string ServiceUid;
}
One thing to note here is that casing does not matter in this case so please use CamelCasing in your domain models as you would normally do in C#.
Thanks for everyone's help.
Firstly I had to make a few changes to the class names as they didn't match the JSON. I also had to change the syntax of two commands which I've detailed below:
I changed the definition of the list of objects from:
public List<services> service = new List<services>();
to:
public List<service> destination { get; set; };
and deserilisation command from:
services servicelist = JsonSerializer.Deserialize<services>(channelResponse.RootElement.GetProperty("services").GetRawText());
to
var servicelist = JsonSerializer.Deserialize<List<service>>(channelResponse.RootElement.GetProperty("services").GetRawText());
The change from services to var might not be the best solution. I think it's the first change, and matching the class names to the JSON, that fundamentally fixed the issue.
I am trying to load data from an XML file into a c# class but am not getting data being loaded in Notifications. The rest of the class (not shown) is correctly populated so I am assuming that my class definition is incorrect. Can anyone shed any light on this?
public partial class ISTimetables
{
[XmlElement]
public List<ISNotification> Notifications { get; set; }
}
[Serializable()]
public partial class ISNotification
{
public ISNotification()
{
On = new List<ISProcessStep>();
Notify = new List<ISNotify>();
}
[XmlElement]
public List<ISProcessStep> On { get; set; }
[XmElement]
public List<ISNotify> Notify { get; set; }
}
[Serializable()]
public partial class ISNotify
{
public string Email { get; set; }
public string SimpleEmail { get; set; }
public string SMS { get; set; }
}
[Serializable()]
public enum ISProcessStep
{
[XmlEnum("Calculated")]
Calculated,
[XmlEnum("Reported")]
Reported,
[XmlEnum("Customer Approved")]
CustomerApproved,
[XmlEnum("Rejected")]
Rejected
}
The data I am trying to load is as follows:
<Notifications>
<Notification>
<On>Calculated</On>
<On>Reported</On>
<Notify SimpleEmail="me#company.com"/>
<Notify Email="you#company.com"/>
<Notify SMS="0123456789"/>
</Notification>
<Notification>
<On>Customer Approved</On>
<Notify Email="him#company.com"/>
</Notification>
</Notifications>
Try this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;
using System.Xml.Serialization;
namespace ConsoleApplication21
{
class Program
{
const string FILEName = #"c:\temp\test.xml";
static void Main(string[] args)
{
XmlSerializer serializer = new XmlSerializer(typeof(ISTimetables));
XmlTextReader reader = new XmlTextReader(FILEName);
ISTimetables tables = (ISTimetables)serializer.Deserialize(reader);
}
}
[XmlRoot("Notifications")]
public partial class ISTimetables
{
[XmlElement("Notification")]
public List<ISNotification> Notifications { get; set; }
}
[XmlRoot("Notification")]
public partial class ISNotification
{
public ISNotification()
{
On = new List<ISProcessStep>();
Notify = new List<ISNotify>();
}
[XmlElement]
public List<ISProcessStep> On { get; set; }
[XmlElement]
public List<ISNotify> Notify { get; set; }
}
[Serializable()]
public partial class ISNotify
{
public string Email { get; set; }
public string SimpleEmail { get; set; }
public string SMS { get; set; }
}
[Serializable()]
public enum ISProcessStep
{
[XmlEnum("Calculated")]
Calculated,
[XmlEnum("Reported")]
Reported,
[XmlEnum("Customer Approved")]
CustomerApproved,
[XmlEnum("Rejected")]
Rejected
}
}
I'm using Newtonsoft.Json with signalR to send data to client side. The following code takes data from database and is supposed to send it but it gives the exception:
an item with the same key has already been added
The code is:
using Makbin.Data;
using Microsoft.AspNet.SignalR;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Web;
using System.Web.Hosting;
namespace Makbin.Web.Hubs
{
public class LogBackgroundTicker : IRegisteredObject
{
private readonly MakbinRepository _repository;
private Timer logsTimer;
private IHubContext hub;
public LogBackgroundTicker()
{
_repository = new MakbinRepository();
HostingEnvironment.RegisterObject(this);
hub = GlobalHost.ConnectionManager.GetHubContext<LogHub>();
logsTimer = new Timer(OnLogsTimerElapsed, null,
TimeSpan.FromSeconds(7), TimeSpan.FromSeconds(7));
}
private void OnLogsTimerElapsed(object sender)
{
var result = _repository.Syslog.Select(x => x).Take(300);
var finalResult = JsonConvert.SerializeObject(result, Formatting.None,
new JsonSerializerSettings()
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
});
hub.Clients.All.broadcastMessage(DateTime.UtcNow.ToString(), finalResult);
}
public void Stop(bool immediate)
{
logsTimer.Dispose();
HostingEnvironment.UnregisterObject(this);
}
}
}
and this is Syslog class:
public class Syslog
{
public Guid LogId { get; set; }
public Guid DeviceId { get; set; }
public string Name { get; set; }
public string Facility { get; set; }
public string Severity { get; set; }
public string DevTime { get; set; }
public string Text { get; set; }
public DateTime Time { get; set; }
public virtual Peripherals Peripheral { get; set; }
}
how can I fix this exception?
public class PurchaseOrderItem
{
public Int64 PONumber { get; set; }
public string Description { get; set; }
public string UM { get; set; }
public int QTY { get; set; }
public decimal Cost { get; set; }
}
foreach (PurchaseOrderItem item in po.PurchaseOrderItems)
{
dgvPOItem.Rows.Add(item);
}
The Foreach above isn't working.
I can't use DataSource since i need to add a blank row after adding the data
So there will be a empty row where users can add values on gridview in the future.
can't you use a BindingList<PurchaseOrderItem> ?
this should allow you to add items to your collection from dgv control (using empty row)
Edit: I've created simple WinForm app,
only DGV control in the main form
Form1.cs code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1 {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
list.Add( new PurchaseOrderItem() {
PONumber = 1,
Description = "First item",
UM = "something",
QTY = 2341,
Cost = 0.99M
} );
dataGridView1.DataSource = list;
dataGridView1.RowsAdded += new DataGridViewRowsAddedEventHandler( dataGridView1_RowsAdded );
}
void dataGridView1_RowsAdded( object sender, DataGridViewRowsAddedEventArgs e ) {
object o = list; // added for breakpoint with variable viewing
// you can watch your list changing here, when you add new rows
}
BindingList<PurchaseOrderItem> list = new BindingList<PurchaseOrderItem>();
}
public class PurchaseOrderItem {
public Int64 PONumber { get; set; }
public string Description { get; set; }
public string UM { get; set; }
public int QTY { get; set; }
public decimal Cost { get; set; }
}
}