Serialize some relationships to JSON, but not all - c#

I have the following problem: I am trying to serialize an object (object1) to Json using Newtonsoft.Json package. I need to be able to send it to a server. The problem is object1 has several referenced objects, some that should be created together with object1, but one of them is "read only" on the server, so it must be send as a relationship.
I am using string json = JsonConvert.SerializeObject
Example:
<code>
[DataContract]
public class Object1
{
// Simple Properties
[JsonProperty(PropertyName = "ext_ref", Order = 1)]
public string ExtRef { get; set; }
[JsonProperty(PropertyName = "external_comment", Order = 1)]
public string ExternalComment { get; set; }
[JsonProperty(PropertyName = "internal_comment", Order = 1)]
public string InternalComment { get; set; }
[JsonProperty(PropertyName = "object2")]
public Object2 Object2 { get; set; }
[JsonProperty(PropertyName = "object3")]
public Object3 Object3 { get; set; }
}
</code>
This is how I get it atm. This is fine for most of the objects, but not all:
{
"data": {
"attributes": {
"ext_ref": "2573421",
"external_comment": "Ext Comment",
"internal_comment": "Internal comment",
"object2": {
"data": {
"attributes": {
"xx":"XX",
"yy":"YY"
},
"id": "1",
"type": "object2s"
},
"object3": {
"data": {
"attributes": {
"xx":"XX",
"yy":"YY"
},
"id": "1",
"type": "object3s"
}
},
},
"type": "object1"
}
Because the object2 is a "special case", where it can only be understood by the server as a link, it needs to look like this:
{
"data": {
"attributes":{
"ext_ref": "2573421",
"external_comment": "Ext Comment",
"internal_comment": "Internal comment",
"object3": {
"data": {
"attributes": {
"xx":"XX",
"yy":"YY"
},
"id": "1",
"type": "object3s"
}
},
"type": "object1",
"relationships":{
"object2": {
"data": {
"id": "1",
"type": "object2s"
}
}
}
}
Now my question is this: Is there an easy way of doing this?
I have tried the following:
Using the Relationship attribute from JsonApiSerializer
Changing the JsonProperty settings for the object2.id property
Deleting the object2.id
I can't help thinking there must some attribute I can use to get the desired result, but atm. I am stuck
[EDIT]
I added an example object structure

Ok, I found the error. I am using Newtonsoft.Json to create the Json with this call:
string json = JsonConvert.SerializeObject(order, Format.None,
new JsonApiSerializerSettings {
NullValueHandling = NullValueHandling.Ignore
});
The part that caused the problem was the Format.None, which made the Json come out as basic Json, and not the usual format. I changed it to null, and I got the result I wanted. Big woop, wanna fight about it?

Related

Cross-referencing two parts of one JSON file in C#?

Newbie question. I have a semi-complex JSON file that I have parsed in my program. The relevant parts are below:
{
"version": "36",
"released": "20220223",
"samples": {
"Samp1": [
{
"code": "A01",
"status": "Optimal",
"bestBy": "20210918",
"expires": "20211018",
"elementKeys": {
"H": [
"Hydrogen-std1-slt4"
]
}
},
{
"code": "A02",
"status": "Optimal",
"bestBy": "20211201",
"expires": "20220501",
"elementKeys": {
"H": [
"Hydrogen-std1-slt5"
]
}
},
{
"code": "A03",
"status": "Optimal",
"bestBy": "20230201",
"expires": "20230801",
"elementKeys": {
"H": [
"Hydrogen-std1-slt6"
]
}
}
],
"Samp2": [ ...
"Samp3": [ ...
"Samp4": [ ...
},
"element": {
"Hydrogen-std1-slt4": {
"format": "1.0",
"position": 4,
"standard": "std1",
...
...
}
What I need to do is populate some windows form controls with data from this file. However, thanks to the odd architecture, I'm a little frustrated over how to populate the controls for "code", "status", "bestBy", etc contained within the "samples" arrays (Samp1, 2, 3, and 4).
Only some of the samples are relevant and the relevancy is defined by whether or not the name of the element key is found further below in the JSON file. So, using the example above, within "element", the object "Hydrogen-std1-slt4" is found in the body of the JSON file with its own key-value pairs. I would like the program to see that and recognize that "Hydrogen-std1-slt4" is also found within the object in the "Samp1" array with the code "A01", the status of "Optimal", the best-by date of "20210918", and that it expires on "20211018". Since it isn't found in any other place in "Samp1", the program can ignore the other objects.
What would be the easiest, most logical way to go about making a conditional for that?
try this code
var jsonParsed = JObject.Parse(json);
string[] elementKeys = ((JObject)jsonParsed["element"]).Properties().Select(x => x.Name).ToArray();
List<Samp> data= GetData(((JObject) jsonParsed["samples"]), elementKeys);
public List<Samp> GetData(JObject samples, string[] elementKeys)
{
List<Samp> result = new List<Samp>();
foreach (var element in samples.Properties())
foreach (var item in element.Value)
if ( item["elementKeys"]["H"]!=null
&& item["elementKeys"]["H"].ToObject<string[]>()
.Any(x => elementKeys.Contains(x)) )
result.Add(item.ToObject<Samp>());
return result;
}
classes
public class Samp
{
public string code { get; set; }
public string status { get; set; }
public string bestBy { get; set; }
public string expires { get; set; }
public ElementKeys elementKeys { get; set; }
}
public class ElementKeys
{
public List<string> H { get; set; }
}

How can I deserialize Array of Arrays in Newtonsoft Json C#? [duplicate]

I have this JSON:
[
{
"Attributes": [
{
"Key": "Name",
"Value": {
"Value": "Acc 1",
"Values": [
"Acc 1"
]
}
},
{
"Key": "Id",
"Value": {
"Value": "1",
"Values": [
"1"
]
}
}
],
"Name": "account",
"Id": "1"
},
{
"Attributes": [
{
"Key": "Name",
"Value": {
"Value": "Acc 2",
"Values": [
"Acc 2"
]
}
},
{
"Key": "Id",
"Value": {
"Value": "2",
"Values": [
"2"
]
}
}
],
"Name": "account",
"Id": "2"
},
{
"Attributes": [
{
"Key": "Name",
"Value": {
"Value": "Acc 3",
"Values": [
"Acc 3"
]
}
},
{
"Key": "Id",
"Value": {
"Value": "3",
"Values": [
"3"
]
}
}
],
"Name": "account",
"Id": "2"
}
]
And I have these classes:
public class RetrieveMultipleResponse
{
public List<Attribute> Attributes { get; set; }
public string Name { get; set; }
public string Id { get; set; }
}
public class Value
{
[JsonProperty("Value")]
public string value { get; set; }
public List<string> Values { get; set; }
}
public class Attribute
{
public string Key { get; set; }
public Value Value { get; set; }
}
I am trying to deserialize the above JSON using the code below:
var objResponse1 = JsonConvert.DeserializeObject<RetrieveMultipleResponse>(JsonStr);
but I am getting this error:
Cannot deserialize the current JSON array (e.g. [1,2,3]) into type
'test.Model.RetrieveMultipleResponse' because the type requires a JSON
object (e.g. {"name":"value"}) to deserialize correctly. To fix this
error either change the JSON to a JSON object (e.g. {"name":"value"})
or change the deserialized type to an array or a type that implements
a collection interface (e.g. ICollection, IList) like List that can
be deserialized from a JSON array. JsonArrayAttribute can also be
added to the type to force it to deserialize from a JSON array. Path
'', line 1, position 1.
Your json string is wrapped within square brackets ([]), hence it is interpreted as array instead of single RetrieveMultipleResponse object. Therefore, you need to deserialize it to type collection of RetrieveMultipleResponse, for example :
var objResponse1 =
JsonConvert.DeserializeObject<List<RetrieveMultipleResponse>>(JsonStr);
If one wants to support Generics (in an extension method) this is the pattern...
public static List<T> Deserialize<T>(this string SerializedJSONString)
{
var stuff = JsonConvert.DeserializeObject<List<T>>(SerializedJSONString);
return stuff;
}
It is used like this:
var rc = new MyHttpClient(URL);
//This response is the JSON Array (see posts above)
var response = rc.SendRequest();
var data = response.Deserialize<MyClassType>();
MyClassType looks like this (must match name value pairs of JSON array)
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class MyClassType
{
[JsonProperty(PropertyName = "Id")]
public string Id { get; set; }
[JsonProperty(PropertyName = "Name")]
public string Name { get; set; }
[JsonProperty(PropertyName = "Description")]
public string Description { get; set; }
[JsonProperty(PropertyName = "Manager")]
public string Manager { get; set; }
[JsonProperty(PropertyName = "LastUpdate")]
public DateTime LastUpdate { get; set; }
}
Use NUGET to download Newtonsoft.Json add a reference where needed...
using Newtonsoft.Json;
Can't add a comment to the solution but that didn't work for me. The solution that worked for me was to use:
var des = (MyClass)Newtonsoft.Json.JsonConvert.DeserializeObject(response, typeof(MyClass));
return des.data.Count.ToString();
Deserializing JSON array into strongly typed .NET object
Use this, FrontData is JSON string:
var objResponse1 = JsonConvert.DeserializeObject<List<DataTransfer>>(FrontData);
and extract list:
var a = objResponse1[0];
var b = a.CustomerData;
To extract the first element (Key) try this method and it will be the same for the others :
using (var httpClient = new HttpClient())
{
using (var response = await httpClient.GetAsync("Your URL"))
{
var apiResponse = await response.Content.ReadAsStringAsync();
var list = JObject.Parse(apiResponse)["Attributes"].Select(el => new { Key= (string)el["Key"] }).ToList();
var Keys= list.Select(p => p.Key).ToList();
}
}
var objResponse1 =
JsonConvert.DeserializeObject<List<RetrieveMultipleResponse>>(JsonStr);
worked!

Not getting result when deserializing json using DataContractJsonSerializer

I have following json:
{
"Australia": {
"count": 2,
"records": {
"File1.ppt": {
"id": "123456789"
},
"File2.doc": {
"id": "987654321"
}
}
},
"PDFs.zip": {
"count": 0,
"records": {}
},
"Peru": {
"count": 2,
"records": {
"File3.PPT": {
"id": "897456123"
},
"File4.PPT": {
"id": "123546789"
}
}
},
"total count": 4
}
and to deserialize the above json I have defined some classes so that I can use these classes while deserializing my json into objects and below are the classes:
namespace GEO_Batch_Creation
{
[DataContract]
class BhpIdJson
{
[DataMember(Name = "objects")]
public Dictionary<string, Country[]> Countries { get; set; }
[DataMember(Name = "total count")]
public int TotalCount { get; set; }
}
[DataContract]
class Country
{
[DataMember(Name = "count")]
public int Count { get; set; }
[DataMember(Name = "records")]
public Dictionary<string, Record> Records { get; set; }
}
[DataContract]
class Record
{
[DataMember(Name = "filename")]
public string FileName { get; set; }
[DataMember(Name = "id")]
public Dictionary<string, string> BhpId { get; set; }
}
}
But when I use following code to deserialize the json I am getting only total count.
using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(json)))
{
// Deserialization from JSON
DataContractJsonSerializer deserializer = new DataContractJsonSerializer(typeof(BhpIdJson));
BhpIdJson bsObj2 = (BhpIdJson)deserializer.ReadObject(ms);
}
Please suggest me where I am doing mistake.
I don't think that this JSON is in correct format. I don't know if you got this from somewhere or made for yourself, but if the last one I recommend you to change the structure.
Even in C# you cant realy create a class that has the objects and the count of the object in the same List or Array etc.
Based on your class your JSON yhould look like this:
{
"objects": [
{
"name": "Australia",
"count": 2,
"records": [
{
"fileName": "File1.ppt",
"id": "123456789"
},
{
"fileName": "File2.doc",
"id": "987654321"
}
]
}
],
"total count": 4
}
As you can see you have to add Name or something to your Country class. I hope it helped.
Edit:
You can create a list like I mentioned above but it's not a good practice I think.

Json modelling issue

I'm currently working with the following json structure and I'm not sure how to model it on my classes, since I've never run into this kind of structure before. Would appreciate any leads or help:
{ "messages": { "1": { "tid": "309", "status": "0", "timestamp": "1379795079", "uid": "1111111111", "txt": "sometext" }, "2": { "tid": "310", "status": "0", "timestamp": "1379795523", "uid": "2222222222", "txt": "sometext2" } }, "status": 1 }
The messages value objects are not a common json structure that i know of, I understand that these are objects, but I don't know how to map them with my classes.
I Use json2csharp, to model my objects for me. Consider the following json object:
{
"employees": [
{ "firstName":"John" , "lastName":"Doe" },
{ "firstName":"Anna" , "lastName":"Smith" },
{ "firstName":"Peter" , "lastName":"Jones" }]
}
I get these objects from the tool:
public class Employee
{
public string firstName { get; set; }
public string lastName { get; set; }
}
public class RootObject
{
public List<Employee> employees { get; set; }
}
Source: http://json2csharp.com/
Technically, your json object is a dictionary, associative array or even hash-table (select appropriate for your target language). Such a data structure is a perfectly reasonable thing to serialize.
However, that particular object would probably have been better serialized as something like:
{ "messages":
[
{ "tid": "309"
, "status": "0"
, "timestamp": "1379795079"
, "uid": "1111111111"
, "txt": "sometext"
}
,
{ "tid": "310"
, "status": "0"
, "timestamp": "1379795523"
, "uid": "2222222222"
, "txt": "sometext2" }
}
]
, "status": 1
}
(unless the sender wanted the option of sending the individual messages items out of order). That's certainly how I would represent it.
This is how I've solved it:
public class MessagesResponse
{
[JsonProperty("messages")]
public Dictionary Messages { get; set; }
[JsonProperty("status")]
public int Status { get; set; }
}
THanks to #rici, I've realized that the use of a dictionary would solve the problem

Convert a Tree Class into a simpler Tree class and Serialize to Json maintaining structure

ok, so i have a class similar to this:
public class Channel
{
public Guid Guid{get;set;}
public string Title{get;set;}
/* GOT A LOT MORE PROPERTIES IN THIS SPACE */
public Guid Parent {get;set;}
public List<Channel> Children{get;set;}
}
i also have a List<Channels> (with a total of about 650 Channels)
the ROOT channel contains about 6 channels and each of the channels contains, children and so on.
as you see in the code of Channel there are a lot of other properties,
which i don't want to serialize IN THIS CASE. that is, all the Data Contracts are already defined in the base class, and i do not/can not change them just for this action.
so, what is my problem you ask?
i need to get a List<Channels> or List<NewType> to be serialized to JSON and maintain the Tree structure.
if it is not possible, at least, how would i serialize the List<Channels> to JSON maintaining the structure?
EDIT:
i am using Newtonsoft.Json
Personally I would suggest serializing the list to an array of Channels...consider the following JSON example:
{
"Channel": {
"Guid": "27182d04-29d9-4760-86d5-484ba43cd9c6",
"Title": "FooBar",
"Parent": "52cfd532-6010-41c5-8fa9-f3bcbb97a630",
"Children": [
{
"Channel": {
"Guid": "27182d04-29d9-4760-86d5-484ba43cd9c6",
"Title": "FooBar",
"Parent": "52cfd532-6010-41c5-8fa9-f3bcbb97a630",
"Children": null
}
},
{
"Channel": {
"Guid": "27182d04-29d9-4760-86d5-484ba43cd9c6",
"Title": "FooBar",
"Parent": "52cfd532-6010-41c5-8fa9-f3bcbb97a630",
"Children": null
}
},
{
"Channel": {
"Guid": "27182d04-29d9-4760-86d5-484ba43cd9c6",
"Title": "FooBar",
"Parent": "52cfd532-6010-41c5-8fa9-f3bcbb97a630",
"Children": null
}
}
]
}
}
EDIT: Here is a little test code which will write this structure:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Script.Serialization;
namespace JSONTest
{
class Program
{
static void Main(string[] args)
{
Channel c = new Channel();
c.Guid = Guid.NewGuid();
c.Parent = Guid.NewGuid();
c.Title = "FooBar";
c.Children = new List<Channel>();
Channel a = new Channel();
Channel b = new Channel();
a.Guid = Guid.NewGuid();
b.Guid = Guid.NewGuid();
a.Parent = Guid.NewGuid();
b.Parent = Guid.NewGuid();
a.Title = "FooBar_A";
b.Title = "FooBar_B";
c.Children.Add(a);
c.Children.Add(b);
/* Serialization happens here!! */
JavaScriptSerializer serializer = new JavaScriptSerializer();
string result = serializer.Serialize(c);
Console.WriteLine(result);
Console.Read();
}
}
public class Channel
{
public Guid Guid { get; set; }
public string Title { get; set; }
/* GOT A LOT MORE PROPERTIES IN THIS SPACE */
public Guid Parent { get; set; }
public List<Channel> Children { get; set; }
}
}
Here is the result of that test after being passed through JSONLint
{
"Guid": "0e72c12c-a7a1-461a-8b84-8b17023e2e2f",
"Title": "FooBar",
"Parent": "d0943246-1adc-4208-bb3b-1249ffe5e7b4",
"Children": [
{
"Guid": "1cf413be-d6b5-405e-8308-7c6dfe817f9a",
"Title": "FooBar_A",
"Parent": "ecf14fce-c97d-46f5-890b-bab8ff99fb4a",
"Children": null
},
{
"Guid": "bd96e6d3-f247-4a0d-9147-92da19793e97",
"Title": "FooBar_B",
"Parent": "5cd3e765-23c2-4145-8b45-9964a7c66c54",
"Children": null
}
]
}
VALID JSON!
EDIT: One thing I have noticed is that JavaScriptSerializer does not parse "Channel", since the whole object is of type Channel and each object in "Children" is of type Channel. If you were to pass this JSON through the Deserialize method, if should build this back into a C# structure with all JSON persisted data.

Categories