C# JSON Anonymous Type - Multiple properties with the same name - c#

I am needing to produce this JSON string with C#:
{
"in0": {
"children": [
{
"ValueObjectDescriptor": {
"fields": [
{
"FieldDescriptor": {
"name": "length",
"xpath": "#lenth"
}
},
{
"FieldDescriptor": {
"name": "height",
"xpath": "#height"
}
},
{
"FieldDescriptor": {
"name": "width",
"xpath": "#width"
}
}
],
"objectName": "Job",
"limit": 1,
"xpathFilter": "#openJob = 'true'"
}
}
]
}
}
Here is my code:
static string BuildJsonString()
{
var json = new
{
in0 = new
{
children = new
{
ValueObjectDescriptor = new
{
fields = new
{
FieldDescriptor = new
{
name = "length",
xpath = "#length",
},
FieldDescriptor = new
{
name = "height",
xpath = "#height",
},
FieldDescriptor3 = new
{
name = "width",
xpath = "#width",
},
objectName = "Job",
limit = "1",
xpathFilter = "#openJob='true'"
}
}
}
}
};
var jsonFormatted = JsonConvert.SerializeObject(json, Newtonsoft.Json.Formatting.Indented);
return jsonFormatted.ToString();
The issue I am having is that the compiler doesn't like me using "FieldDescriptor" multiple times, I get the error "An anonymous type cannot have multiple properties with the same name".
I am very new to JSON, so any advice would be greatly appreciated.

Note that not only is having multiple fields with the same name invalid C# code, having duplicate keys in the same object is also invalid JSON. You can be sure that there is no JSON that would need you to write duplicate field names to serialise it.
The "FieldDescriptor" JSON keys are actually part of different JSON objects, and these JSON objects are all in a JSON array under the key "fields":
[
{
"FieldDescriptor": {
"name": "length",
"xpath": "#lenth"
}
},
{
"FieldDescriptor": {
"name": "height",
"xpath": "#height"
}
},
{
"FieldDescriptor": {
"name": "width",
"xpath": "#width"
}
}
]
The [ ... ] denotes the array, and each pair of { ... } denotes a JSON object. So you should create an (implicitly typed) array of anonymous objects, each one with the FieldDescriptor property, rather than one object having all three of the proeperties:
fields = new[] // <--- create an array
{
new {
FieldDescriptor = new
{
name = "length",
xpath = "#length",
}},
new { // notice the new pairs of curly braces
FieldDescriptor = new
{
name = "height",
xpath = "#height",
}}, // here's the closing brace
new {
FieldDescriptor3 = new
{
name = "width",
xpath = "#width",
}},
objectName = "Job",
limit = "1",
xpathFilter = "#openJob='true'"
}

It looks like in the json "fields" is an array of objects where each object contains a "FieldDescriptor" field. In your C# code you are creating "fields" as an object with multiple fields not an array of objects.

Related

serilization daughter classes

I am trying to serialize a class that has daughter classes but it does not allow me when I go to complete the json it gives me an error
This is the json file as it should look:
{
"User": "jhuan.caasillas",
"Passwd": "#########",
"IdAplicativo": 2001,
"Firma": "asdlkhg=saldkja=="
}
"Mensaje": {
"CodigoMensaje": 320,
"DescMensaje": "Exito"
},
"Roles": [
{
"Descripcion": "juan casillas"
},
{
"Descripcion": "al21"
},
{
"Descripcion": "comandos"
},
{
"Descripcion": "identificado"
}
]
}
I have this class with these methods created
enter image description here
when I go to fill these methods with the json it doesn't allow me and I get the error
Cannot implicitly convert type 'serialize.Roles' to 'serialize.Roles[]' serialize
enter image description here
I would like to know how I can fill the json array that I showed previously
If Roles is array it must be initialized as array
DominioRes res1 = new DominioRes
{
Roles = new Roles[]
{
new Roles
{
Description="juan casillas"
},
new Roles
{
Description="al21"
},
new Roles
{
Description="comandos"
},
new Roles
{
Description="identificado"
}
}
};

how to replace the entire array using MongoDB c# driver

Say, the existing document in DB is like this:
{
"_id": "1",
"settings": {
"languages": [ "english", "french" ]
}
}
Now I want to update the document to this:
{
"_id": "1",
"settings": {
"languages": [ "korean", "german" ]
}
}
I tired this following code:
var lan = new List<string> { "finish", "russian", "korean" }
collection.UpdateOne(
Builders<MyObject>.Filter.Eq("_id", "1"),
Builders<MyObject>.Update.Set("settings.languages", lan));
But got following exception:
MongoDB.Bson.Serialization.Serializers.EnumerableInterfaceImplementerSerializer2[System.Collections.Generic.List1[System.String],System.String]' cannot be converted to type 'MongoDB.Bson.Serialization.IBsonSerializer`1[System.String]
I also tried using BsonArray to initialize the new languages array:
var bsonArray = new BsonArray
{
"korean",
"german"
};
collection.UpdateOne(
Builders<MyObject>.Filter.Eq("_id", "1"),
Builders<MyObject>.Update.Set("settings.languages", bsonArray));
The update could be executed without error, but the languages in document is changed to:
{
"_id": "1",
"settings": {
"languages": "[korean, german]"
}
}
It becomes "[ xx, xx ]", instead of [ "xx", "xx" ]. It is not what I expected.
You're getting that error message because you're using strongly typed builders on type MyObject which probably looks more or less like below:
public class MyObject
{
public string _id { get; set; }
public Settings settings { get; set; }
}
public class Settings
{
public string[] languages { get; set; }
}
So since you have a strongly typed Builder you are getting an exception because of the type mismatch between List and Array. Two ways to fix that:
Either use .ToArray() on list to get the same type as the one you have in your MyObject:
var lan = new List<string> { "finish", "russian", "korean" };
collection.UpdateOne(
Builders<MyObject2>.Filter.Eq("_id", "1"),
Builders<MyObject2>.Update.Set("settings.languages", lan.ToArray()));
or skip the type validation using BsonDocument class:
var collection = mydb.GetCollection<BsonDocument>("col");
var lan = new List<string> { "finish", "russian", "korean" };
collection.UpdateOne(
Builders<BsonDocument>.Filter.Eq("_id", "1"),
Builders<BsonDocument>.Update.Set("settings.languages", lan));

Deserialize JSON with variable property name and nested list to object

I have a bunch of API which generates the following 2 kinds of reply in response body:
{ "error": null, "object_type": { /* some object */ } }
{ "error": null, "object_type": [{ /* some object */ }, { /* some object */ }, ...] }
While I have a class corresponding to the object structure, I want to deserialize the API endpoints directly into either an object of the class or a List<class>, without creating some "result" classes to match the response JSON structure. Is this possible?
For example there is 2 API:
/api/getAllCompanies
returns
{ "error": null, "company": [ { "name": "Microsoft", "country": "US" }, { "name": "Apple", "country": "US" } ]
while
/api/getUserCompany
returns
{ "error": null, "company": { "name": "Microsoft", "country": "US" } }
I have a class in code:
public class Company {
string Name { get; set; }
string Country { get; set; }
}
How can I directly deserialize the data into a Company object or a List<Company> without creating a bunch of other class?
(The JSON property name (company) is known so don't need to extract it elsewhere.)
I've been trying to first deserialize the response JSON into an ExpandoObject then copy the properties to an instance of destination class using the code here then convert it using the following code, but this seems not to work with lists.
private static async Task<T> GetApiObject<T>(string api, string extractedObjName) where T: class, new()
{
var retstr = await /* get API response as string */;
dynamic retobj = JsonConvert.DeserializeObject<ExpandoObject>(retstr, new ExpandoObjectConverter());
var ret = new T();
Mapper<T>.Map((ExpandoObject)((IDictionary<string, object>)retobj)[extractedObjName], ret);
return ret;
}
You can use JObejct to extract the information you need before deserialize it into the object.
var str = "{ \"error\": null, \"company\": [{ \"name\": \"Microsoft\", \"country\": \"US\" } ,{ \"name\": \"Apple\", \"country\": \"US\" } ]}";
var temp = JObject.Parse(str).GetValue("company");
var companies = temp.Select(x => x.ToObject<Company>()).ToList();
Same goes for /api/getUserCompany
var str = "{ \"error\": null, \"company\": { \"name\": \"Microsoft\", \"country\": \"US\" } }";
var temp = JObject.Parse(str).GetValue("company");
var company = temp.ToObject<Company>();

Search for a nested value inside of a JSON.net object in C#

I've got a JSON stream coming back from a server, and I need to search for a specific value of the node "ID" using JSON.net to parse the data.
And I can almost make it work, but not quite because the results coming back are deeply nested in each other -- this is due to the fact that I'm getting a folder structure back. I've boiled the JSON down to a much simpler version. I'm getting this:
{
"data": {
"id": 0,
"name": "",
"childFolders": [{
"id": 19002,
"name": "Locker",
"childFolders": [{
"id": 19003,
"name": "Folder1",
"childFolders": [],
"childComponents": [{
"id": 19005,
"name": "route1",
"state": "STOPPED",
"type": "ROUTE"
}]
}, {
"id": 19004,
"name": "Folder2",
"childFolders": [],
"childComponents": [{
"id": 19008,
"name": "comm1",
"state": "STOPPED",
"type": "COMMUNICATION_POINT"
}, {
"id": 19006,
"name": "route2",
"state": "STOPPED",
"type": "ROUTE"
}, {
"id": 19007,
"name": "route3",
"state": "STOPPED",
"type": "ROUTE"
}]
}],
"childComponents": []
}],
"childComponents": []
},
"error": null
}
I can almost get there by going:
var objects = JObject.Parse(results);
var subobjects = objects["data"]["childFolders"][0]["childFolders"][1];
I can see in the debug view that it'll parse the object, but won't let me search within.
My ultimate goal is to be able to search for "route3" and get back 19007, since that's the ID for that route. I've found some results, but all of them assume you know how far nested the object is. The object I'm searching for could be 2 deep or 20 deep.
My ultimate goal is to be able to search for "route3" and get back 19007
You can use linq and Descendants method of JObject to do it:
var dirs = JObject.Parse(json)
.Descendants()
.Where(x=>x is JObject)
.Where(x=>x["id"]!=null && x["name"]!=null)
.Select(x =>new { ID= (int)x["id"], Name = (string)x["name"] })
.ToList();
var id = dirs.Find(x => x.Name == "route3").ID;
You can use the SelectToken or SelectTokens functions to provide a JPath to search for your desired node. Here is an example that would provide you the route based on name:
JObject.Parse(jsonData)["data"].SelectToken("$..childComponents[?(#.name=='route3')]")
You can find more documentation on JPath here
Simply write a recursive function:
private Thing FindThing(Thing thing, string name)
{
if (thing.name == name)
return thing;
foreach (var subThing in thing.childFolders.Concat(thing.childComponents))
{
var foundSub = FindThing(subThing, name);
if (foundSub != null)
return foundSub;
}
return null;
}
class RootObject
{
public Thing data { get; set; }
}
class Thing
{
public int id { get; set; }
public string name { get; set; }
public List<Thing> childFolders { get; set; } = new List<Thing>();
public List<Thing> childComponents { get; set; } = new List<Thing>();
}
And using it:
var obj = JsonConvert.DeserializeObject<RootObject>(jsonString);
var result = FindThing(obj.data, "route3");

How make array insert array json in web service C#

How can I create a JsonArray with a child data object array? I am using Web service and C#.
I want the result of the JsonArray to look like the following:
[{
"name": "Deadpool",
"url": {
"small": "http://api.android.info/images/small/deadpool.jpg",
"medium": "http://api.android.info/images/medium/deadpool.jpg",
"large": "http://api.android.info/images/large/deadpool.jpg"
},
"time": "February 12, 2016"
},
{
"name": "The Jungle Book",
"url": {
"small": "http://api.android.info/images/small/book.jpg",
"medium": "http://api.android.info/images/medium/book.jpg",
"large": "http://api.android.info/images/large/book.jpg"
},
"time": "April 15, 2016"
},
{
"name": "X-Men: Apocalypse",
"url": {
"small": "http://api.android.info/images/small/xmen.jpg",
"medium": "http://api.android.info/images/medium/xmen.jpg",
"large": "http://api.android.info/images/large/xmen.jpg"
},
"time": "May 27, 2016"
}]
First, create the models that can output the given data. You need a MovieModel, a movie can have multiple image sizes and urls stored, we use a dictionary for this.
UPDATED
MovieModel.cs
public class MovieModel
{
public string Name { get; set; }
public Dictionary<string,string> Url { get; set; }
public string Time { get; set; }
}
Now you need to install Newtonsoft.Json from Nuget packages. Then import it.
using Newtonsoft.Json;
Initialize the model and convert to Json using SerializeObject() method.
var movieList = new List<MovieModel>
{
new MovieModel
{
MovieName = "Deadpool",
Time = DateTime.UtcNow.ToString("t"),
Url = new Dictionary<string, string>
{
{ "small", "http://api.android.info/images/small/deadpool.jpg" },
{ "medium", "http://api.android.info/images/medium/deadpool.jpg" }
}
}
// .. add more movies .. //
};
// convert to camelcase and set indentation
var output = JsonConvert.SerializeObject(
movieList,
Formatting.Indented,
new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
}
);
// testing output on console
Console.WriteLine(output);
In a real application, you would create Movie instances by getting data from a database, not initializing it for yourself as used in this example.

Categories

Resources