Serializing JSON in .NET - c#

I have wrote a basic web service using .net which I intend to use in a mobile app. It currently outputs Json however the structure it not quite what I need.
The models I've created
[DataContract]
class PoiList
{
[DataMember]
public List<Poi> Pois { get; set; }
}
[DataContract]
class Poi
{
[DataMember]
public string title { get; set; }
[DataMember]
public string latitude { get; set; }
[DataMember]
public string longitude { get; set; }
}
Then i added some test data:
PoiList poiList = new PoiList
{
Pois = new List<Poi>()
};
Poi p = new Poi
{
title = "whatever",
latitude = "-2.45554",
longitude = "52.5454645"
};
poiList.Pois.Add(p);
p = new Poi
{
title = "weeee",
latitude = "-2.45554",
longitude = "52.5454645"
};
poiList.Pois.Add(p);
string ans = JsonConvert.SerializeObject(poiList, Formatting.Indented);
This is what the returned string looks like:
{ "Pois": [ { "title": "shit", "latitude": "-2.45554", "longitude": "52.5454645" }, { "title": "weeee", "latitude": "-2.45554", "longitude": "52.5454645" } ] }
...and this is what I want the outputted Json to look like:
string TempString = #"{ ""pois"":
[{ ""poi"":
{
""title"": ""Test title"",
""latitude"": ""-2.4857856"",
""longitude"": ""54.585656""
}},
{ ""poi"":
{
""title"": ""Halfords"",
""latitude"": ""-2.575656"",
""longitude"": ""53.5867856""
}}]}";
Basically the only difference being the "poi" next to each object in the list. Is there a simple way to include this? I should add I am using the newtonsoft.json package.

I would suggest you go with the JSON that's being generated, as your target JSON contains unnecessary objects, IMO.
Your target JSON has an object with a single field "pois", which contains a list of objects, each with a single field "poi" that contains an object with the fields "title", "latitude", and "longitude".
To access a single title field, you would need to do the following:
poisObj.pois[0].poi.title
If you go with the JSON that's generated by your object structure, you would access a single title field like so:
poisObj.pois[0].title
That having been said, if you absolutely must target that JSON structure, you'll need another DataContract object, as follows:
[DataContract]
class PoiList
{
[DataMember]
public List<PoiPoi> Pois { get; set; }
}
[DataContract]
class PoiPoi
{
[DataMember]
public Poi poi { get; set; }
}
[DataContract]
class Poi
{
[DataMember]
public string title { get; set; }
[DataMember]
public string latitude { get; set; }
[DataMember]
public string longitude { get; set; }
}

No need to declare many tiny classes just to output a json string. You can create an anonymous object to serialize like below:
var obj = new { pois = new List<object>() };
obj.pois.Add(new { poi = new {title = "Test title", latitude = "-2.4857856", longitude = "54.585656" } });
obj.pois.Add(new { poi = new {title = "Halfords" , latitude = "-2.4857856", longitude = "53.5867856" } });
string json = JsonConvert.SerializeObject(obj, Newtonsoft.Json.Formatting.Indented);
Console.WriteLine(json);

Go with the default structure the only thing the "poi" gives you is what "type" the object is, which JSON doesn't really have a concept of. If you want to include type information, try :-
var jsonSerializerSettings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Objects,
TypeNameAssemblyFormat = FormatterAssemblyStyle.Full,
};
var json = JsonConvert.SerializeObject(o, Formatting.None, jsonSerializerSettings);
this will give you a field _type_ which is useful especially if you have a list of various types of objects. Json.Net then knows how to recreate the objects using this _type_ field.

Related

How to add a property data: for json?

I've created a list of object in C# but I'm struggling to understand how I can add a property (that may not be the right term) to the beginning of it:
This might be really obvious and I'm not sure what I need to Google! Any help would be appreciated!
What I'm trying to do:
{
'data' : [ <--Add this in (is this a property of the object?)
{
'valueName1': 'value1',
'valueName2': 'value2',
'valueName3': 'value3',
},
{
'valueName1': 'value1',
'valueName2': 'value2',
'valueName3': 'value3',
},
]}
What I've got currently!
[
{
'valueName1': 'value1',
'valueName2': 'value2',
'valueName3': 'value3',
},
{
'valueName1': 'value1',
'valueName2': 'value2',
'valueName3': 'value3',
},
]
This is what I've got in C# at the moment:
result= new List<TestList> { };
foreach (var issueData2 in myDeserializedClass.issues)
{
result.Add(new TestList { valueName1 = issueData2.fields.summary,
valuename2 = issueData2.fields.created,
valuename3 = issueData2.fields.updated, });
}
string jsonString = JsonConvert.SerializeObject(newtonresult);
With this class:
public class TestList
{
public String valuename1 { get; set; }
public String valuename2 { get; set; }
public String valuename3 { get; set; }
}
Please don't violate C# naming conventions (properties have PascalCaseNames) just to get your JSON to appear correctly; common json serializers support attributes that allow you to name your C# properties differently to json:
public class TestList
{
[JsonProperty("valuename1")]
public String ValueName1 { get; set; }
[JsonProperty("valuename2")]
public String ValueName2 { get; set; }
[JsonProperty("valuename1")]
public String ValueName3 { get; set; }
}
..that's if you even need to; you can usually also configure serializers so they produce camelCaseJsonPropertyNames even if the C# names are PascalCase - for example
And as GSerg comments, you can put your testlist list in another class:
public class Wrapper {
[JsonProperty("data")]
public List<TestList> Data { get; set;}
}
Then have a creation of:
result= new List<TestList> { };
foreach (var issueData2 in myDeserializedClass.issues)
{
result.Add(new TestList { valueName1 = issueData2.fields.summary,
valuename2 = issueData2.fields.created,
valuename3 = issueData2.fields.updated, });
}
var ser = new Wrapper { Data = result };
string jsonString = JsonConvert.SerializeObject(ser);
You actually don't even need the class Wrapper, if you want.. You can also use an anonymous type:
string jsonString = JsonConvert.SerializeObject(new{ data = result });
So, you basically want property data which is an array of object TestList class
public class Test{
public IEnumerable<TestList> data {get; set'}
}
Now you can serialize the data
string jsonString = JsonConvert.SerializeObject<Test>(newtonresult);

Parse Json works partly - empty sub object

I want to parse a json file. My first attempt with a simplified version was only partial successfull.
The simplifiend json structure looks like this
{
"rowCount": 102,
"data": [
{"id": "56", "bezeichnung": "Main Center", "strasse": "foostreet"},
{"id": "34", "bezeichnung": "Side Location", "strasse": "5th aveneue"}
]
}
For the outer json { "rowCount":102, "data":[]} i have a class jsonEnvelope which looks like this
public class JsonEnvelope
{
public int RowCount { get; set; }
public Location[] Data{ get; set; }
}
To parse the json inside the array data "data":[] i have class location which looks like this
public class Location
{
public string id;
public string bezeichnung;
public string strasse;
}
My code to parse the json looks like this
string jsonString = GetJsonFromFile();
var jsonEnvelope = new JsonEnvelope();
var options = new JsonSerializerOptions();
options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
jsonEnvelope = JsonSerializer.Deserialize<JsonEnvelope>(jsonString, options);
foreach (Location h in jsonEnvelope.Data)
{
Console.WriteLine(String.Format("{0} in {1}", h.bezeichnung, h.strasse));
}
Console.WriteLine("row count = " + jsonEnvelope.RowCount);
What is working?
The line jsonEnvelope.RowCount works. The number 102 is written to the console
The foreach is not working the values of h.bezeichnung and h.strasse are not written to the console
Question
while writing my question i figured it out - i will self answer it briefly
The problem was that i used a field in class location instead of property.
Changing the class location to this solved the issue
public class Location
{
public string Id { get; set; }
public string Bezeichnung { get; set; }
public string Strasse { get; set; }
}
Please note that with:
.NET 5 or
System.Text.Json package version 5 added to Core3.1 projects you can use IncludeFields option:
var serializeOptions = new JsonSerializerOptions
{
IncludeFields = true,
};
var o = JsonSerializer.Deserialize<Location>(json, serializeOptions);

Access JSON keys in C# from ServiceNow Rest API

I am calling the ServiceNow Incidents table and pulling back one incident like this. https://mydevInstance.service-now.com/api/now/v1/table/incident?sysparm_limit=1
var client = new RestClient("https://mydevInstance.service-now.com/api/now/v1/table/incident?sysparm_limit=1");
client.Timeout = -1;
var request = new RestRequest(Method.GET);
request.AddHeader("Authorization", "Basic myAuthKey");
IRestResponse response = client.Execute(request);
The JSON it returns in RESTSharp looks like this.
{
"result": [
{
"parent": "",
"made_sla": "true",
"caused_by": "",
"watch_list": "",
"upon_reject": "cancel",
"resolved_by": {
"link": "https://mydevInstance.service-now.com/api/now/v1/table/sys_user/5137153cc611227c000bbd1bd8cd2007",
"value": "5137153cc611227c000bbd1bd8cd2007"
},
"approval_history": "",
"number": "INC0000060"
}
]
}
How do I create a C# list or array of all the Keys under result? I can't Serialize the object with JSON.Net because additional keys can be added over time.
You need to grab the sample of the JSON content, then make a C# class using the 'Paste Special' option I described.
Then you can use the JsonConvert.DeserializeObject<T> (in a nuget package by Newtonsoft) to deserialize your web service response in a C# object instance.
Here are the C# classes I generated with your JSON object unaltered:
public class Rootobject
{
public Result[] result { get; set; }
}
public class Result
{
public string parent { get; set; }
public string made_sla { get; set; }
public string caused_by { get; set; }
public string watch_list { get; set; }
public string upon_reject { get; set; }
public Resolved_By resolved_by { get; set; }
public string approval_history { get; set; }
public string number { get; set; }
}
public class Resolved_By
{
public string link { get; set; }
public string value { get; set; }
}
You use this type like this:
var json = "t-b-d"; // From Web Service call
Rootobject response = JsonConvert.DeserializeObject<Rootobject>(json);
// use the response object.
** UPDATED **
If you need a more flexible model, all JSON will deserialize into Dictionary<string, string>, but I have found that serialization / deserialization results are more reliable when the model is consistent
var response = JsonConvert.DeserializeObject<Dictionary<string,string>>(json);
Here is what does work using System.Text.Json
var incidentFields = new List<string>();
var doc = JsonDocument.Parse(json);
foreach (var o in doc.RootElement.GetProperty("result").EnumerateArray())
{
foreach (var p in o.EnumerateObject())
{
incidentFields.Add(p.Name.ToString());
}
}
I created a library that handles that by default. (You can add custom types also)
https://autodati.github.io/ServiceNow.Core/

write data from JSON in C#

I have JSON like this:
{
'surveys': [
{
'title': 'first',
'id': 100,
},
{
'title': 'second',
'id': 101,
},
{
'title': 'third',
'id': 102,
},
]
}
I want to have the output like this:
title: first
title: second
title: third
and my program in C# is like this:
WebClient client = new WebClient();
var json = client.DownloadString("http://www.test.com/api/surveys/?api_key=123");
Debug.WriteLine(json); //write all data from json
//add
var example = JsonConvert.DeserializeObject<Example>(json);
Debug.WriteLine(example.Data.Length);
class Example
{
public surveys[] Data { get; set; }
}
class surveys
{
public string title { get; set; }
public int id { get; set; }
}
I get this error:
Thrown: "Object reference not set to an instance of an object." (System.NullReferenceException) Exception Message = "Object reference not set to an instance of an object.", Exception Type = "System.NullReferenceException", Exception WinRT Data = ""
at this line: Debug.WriteLine(example.Data.Length);
where is the problem?
One problem I see is that your outer class has a property named Data, which is an array of 'surveys' objects, but your Json has a list of 'surverys' objects under the property 'surveys'. Hence the 'Data' property is never populated.
Consider the following C# class structure:
class Example
{
public survey[] surveys{ get; set; }//Data renames to surveys
}
class survey //Singular
{
public string title { get; set; }
public int id { get; set; }
}
Why can't you do so?:
JObject data = JObject.Parse(json);
foreach (var survey in data["surveys"].Children())
{
Debug.WriteLine("title: " + survey["title"]);
}
You need to use JSON.Net and use the class JsonConvert and the method DeserializeObject<T>.
If you run this:
JsonConvert.DeserializeObject<JObject>();
Then you will get back a list of de-serialized JObject objects.
Use, NuGet to download the package. I think it is called JSON.net.
Here is the weblink
WebClient client = new WebClient();
var json = client.DownloadString("http://www.test.com/api/surveys/?api_key=123");
Debug.WriteLine(json); //write all data from json
//add
var example = JsonConvert.DeserializeObject<Survey>(json);
Debug.WriteLine(example.length); // this could be count() instead.
class Survey
{
public string title { get; set; }
public int id { get; set; }
}
This should work!
Use json2csharp to generate c# classes from json.
You will also need to use Json.NET.
public class Survey
{
public string title { get; set; }
public int id { get; set; }
}
public class RootObject
{
public List<Survey> surveys { get; set; }
}
Then you can do:
var client = new WebClient();
string json = client.DownloadString(some_url);
RootObject root = JsonConvert.DeserializeObject<RootObject>(json);
foreach (Survey s in root.surveys)
{
// Do something with your survey
}
Don't forget to use Newtonsoft.Json namespace once you add a reference to it within your project.
using Newtonsoft.Json;
Edit: I have tested it using:
string json = "{'surveys': [{'title': 'first','id': 100,},{'title': 'second','id': 101,},{'title': 'third','id': 102,},]}";
instead of using the WebClient, and it works.

How do I deserialize a custom node in Json to c#, whose name keeps changing?

Below is a section of json I receive from an endpoint.
If you look at the Json below, 'User-Defined-Network-Name' is a custom node and the name will change each time.
How do I define a C# object for this Json?
"addresses": {
"public": [{
"version": 6,
"address": "2005:4600:788e:0910:1a72:81c0:ff03:c7y6"
},
{
"version": 4,
"address": "197.68.xx.xxx"
}],
"private": [{
"version": 4,
"address": "10.xx.xx.xxx"
}],
"User-Defined-Network-Name": [{
"version": 4,
"address": "192.xxx.x.xxx"
}]
}
This is how far I have come -
[Serializable]
public class Addresses
{
public List<Public> #public { get; set; }
public List<Private> #private { get; set; }
}
Im using 'JavascriptSerializer' class to deserialize json.
Thanks,
Ryan
addresses can be deserialized to a type like Dictionary<string,List<YourClass>> where YourClass holds version and addresss.
var obj = new JavaScriptSerializer().Deserialize<Root>(jsonstring);
--
public class Root
{
public Dictionary<string,List<VersionAddress>> addresses;
//Your other fields/properties
}
public class VersionAddress
{
public string version;
public string address;
}
You could take advantage of the dynamic nature of C#:
// this could come from user input:
string userDefinedName = "User-Defined-Network-Name";
    string json = "YOUR JSON COMES HERE";
var serializer = new JavaScriptSerializer();
dynamic result = serializer.DeserializeObject(json);
int version = result["addresses"][userDefinedName][0]["version"];
string address = result["addresses"][userDefinedName][0]["address"];
Console.WriteLine(version);
Console.WriteLine(address);
and if you wanted to loop through the results:
foreach (dynamic item in result["addresses"][userDefinedName])
{
int version = item["version"];
string address = item["address"];
Console.WriteLine(version);
Console.WriteLine(address);
}
Why don't you make network names a dictionary, with key of network name ?
Then you can just iterate over it.
I would not recommend using JavaScriptSerializer, as it has been deprecated. If you want a third-party solution, JSON.Net is pretty good from what I hear.
However, I'm one that's weird about dependencies, so I typically roll my own if it doesn't exist already. Fortunately, this one isn't too hard due to DataContractJsonSerializer from the System.Runtime.Serialization namespace.
All you need to do is first define all the objects in a nested fashion:
using System.Reflection;
using System.Runtime.Serialization; // You will have to add a reference
using System.Runtime.Serialization.Json; // to System.Runtime.Serialization.dll
[DataContract]
public class AddressInfo
{
[DataMember(Name = "address")]
public string Address { get; set; }
[DataMember(Name = "version")]
public int Version { get; set; }
}
[DataContract]
public class AddressList
{
[DataMember(Name = "public")]
public IEnumerable<AddressInfo> Public { get; set; }
[DataMember(Name = "private")]
public IEnumerable<AddressInfo> Private { get; set; }
[DataMember(Name = "User-Defined-Network-Name")]
public IEnumerable<AddressInfo> UserDefined { get; set; }
}
Then a couple helper methods to do the deserialization:
// This will change the DataMember.Name at runtime!
// This will only work if you know the node name in advance.
static void SetUserDefinedNodeName(string userDefinedNodeName)
{
var type = typeof(AddressList);
var property = type.GetProperty("UserDefined", BindingFlags.Default);
var attribute = property.GetCustomAttribute<DataMemberAttribute>();
if (attribute != null)
attribute.Name = userDefinedNodeName;
}
static T Deserialize<T>(string jsonText, string userDefinedNodeName)
{
SetUserDefinedNodeName(userDefinedName);
var jsonBytes = Encoding.UTF8.GetBytes(jsonText);
using (var stream = new MemoryStream(jsonBytes))
{
var serializer = new DataContractJsonSerializer(typeof(T));
var obj = serializer.ReadObject(stream) as T;
return obj;
}
}
Then you use it like so:
var jsonText = // get your json text somehow
var addressList = Deserialize<AddressList>(jsonText);

Categories