Mongodb c# - ReplaceOne create duplicate element '_t' error - c#

I try to make an API using ASP NET CORE 7 and mongodb.
I come with a complicated problem that i simply don't understand.
I got a duplicated element name '_t' error when i get my documents after i used ReplaceOneAsync method.
I have Ship documents using polymorphism as :
using MongoDB.Bson.Serialization.Attributes;
using Shipest.Api.Models.DTO.QueriesDTO;
using Shipest.Api.Utils.ExceptionUtils;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
namespace Shipest.Api.Models.DTO;
[BsonIgnoreExtraElements(true)]
[BsonDiscriminator(Required = true, RootClass = true)]
[BsonKnownTypes(typeof(ProbatioDTO), typeof(SpeculatorDTO), typeof(ExtractorDTO), typeof(ManusDTO))]
[JsonDerivedType(typeof(ProbatioDTO))]
[JsonDerivedType(typeof(SpeculatorDTO))]
[JsonDerivedType(typeof(ExtractorDTO))]
[JsonDerivedType(typeof(ManusDTO))]
public class BaseShipDTO
{
[BsonIgnore]
private string id;
[BsonId]
[BsonRepresentation(MongoDB.Bson.BsonType.ObjectId)]
public string Id {
get {
if (new Regex("^[0-9a-fA-F]{24}$").IsMatch(id))
return id;
else
throw new ShipestException("Invalid Id : " + id, 400);
}
set => id = value;
}
public string Name { get; set; }
public virtual PlanetGetDTO? Planet { get; set; }
public DateTime Creation_Date { get; set; }
public int Health { get; set; }
public int Max_Health { get; set; }
[BsonElement("_t")]
public ShipType Type { get; set; }
public long? Owner_Id { get; set; }
public PlanetGetDTO? Planet_Arrival { get; set; }
public DateTime? Arrival_Date { get; set; }
public int Speed { get; set; }
public int Energy { get; set; }
public int Max_Energy { get; set; }
public DateTime? Next_Scan_Date { get; set; }
public int Scan_Cost { get; set; }
public DateTime? Next_Heal_Date { get; set; }
public int Creatium_Cost { get; set; }
}
with ShipType enumeration as :
public enum ShipType
{
Manus,
Probatio,
Speculator,
Extractor
}
When i simply query my document using id, all works. Here my aggregation json used :
[
%m,
{
"$lookup": {
"from": "planets",
"localField": "Coordinates",
"foreignField": "_id",
"as": "Planets"
}
},
{
"$lookup": {
"from": "planets",
"as": "Neighbours",
"let": {
"main_x": "$Coordinates.X",
"main_y": "$Coordinates.Y"
},
"pipeline": [
{
"$match": {
"$expr": {
"$or": [
{
"$eq": [
"$_id",
{
"X": {
"$add": [ "$$main_x", 1 ]
},
"Y": {
"$add": [ "$$main_y" ]
}
}
]
},
{
"$eq": [
"$_id",
{
"X": {
"$add": [ "$$main_x", -1 ]
},
"Y": {
"$add": [ "$$main_y" ]
}
}
]
},
{
"$eq": [
"$_id",
{
"X": {
"$add": [ "$$main_x" ]
},
"Y": {
"$add": [ "$$main_y", 1 ]
}
}
]
},
{
"$eq": [
"$_id",
{
"X": {
"$add": [ "$$main_x" ]
},
"Y": {
"$add": [ "$$main_y", -1 ]
}
}
]
}
]
}
}
}
]
}
},
{
"$lookup": {
"from": "planets",
"localField": "Planet_of_Arrival_Coordinate",
"foreignField": "_id",
"as": "planet_of_arrival"
}
},
{
"$lookup": {
"from": "planets",
"as": "Neighbours_Arrival",
"let": {
"main_x": "$Planet_of_Arrival_Coordinate.X",
"main_y": "$Planet_of_Arrival_Coordinate.Y"
},
"pipeline": [
{
"$match": {
"$expr": {
"$or": [
{
"$eq": [
"$_id",
{
"X": {
"$add": [ "$$main_x", 1 ]
},
"Y": {
"$add": [ "$$main_y" ]
}
}
]
},
{
"$eq": [
"$_id",
{
"X": {
"$add": [ "$$main_x", -1 ]
},
"Y": {
"$add": [ "$$main_y" ]
}
}
]
},
{
"$eq": [
"$_id",
{
"X": {
"$add": [ "$$main_x" ]
},
"Y": {
"$add": [ "$$main_y", 1 ]
}
}
]
},
{
"$eq": [
"$_id",
{
"X": {
"$add": [ "$$main_x" ]
},
"Y": {
"$add": [ "$$main_y", -1 ]
}
}
]
}
]
}
}
}
]
}
},
{
"$addFields": {
"Planet": {
"$first": "$Planets"
},
"Planet_Arrival": {
"$first": "$planet_of_arrival"
}
}
},
{
"$addFields":
{
"Planet.Neighbours": "$Neighbours",
"Planet_Arrival.Neighbours": "$Neighbours_Arrival"
}
},
{
"$unset": [
"Coordinates",
"Planet_of_Arrival_Coordinate",
"Planets",
"planet_of_arrival",
"Neighbours_Arrival",
"Neighbours"
]
},
{
"$set":
{
"Planet_Arrival": {
"$cond": {
"if": {
"$eq": [
{
"$type": "$Planet_Arrival._id"
},
"object"
]
},
"then": "$Planet_Arrival",
"else": "$$REMOVE"
}
},
"Planet": {
"$cond": {
"if": {
"$eq": [
{
"$type": "$Planet._id"
},
"object"
]
},
"then": "$Planet",
"else": "$$REMOVE"
}
}
}
}
]
i know my aggregate can surely be simplified but i'm a beginner with these noSQL syntaxe ahah.
And of course %m is replaced in code as :
private string getAggregateWithMatch(string match)
{
return File.ReadAllText(#".\Database\JsonQueries\shipAggregate.json").Replace("%m", match);
}
public async Task<BaseShipDTO?> GetAsync(string shipId)
{
// use the json
var query = getAggregateWithMatch("{'$match': { '_id': ObjectId('" + shipId + "') }}");
var listResulted = await DataBaseUtils.DoGenericAggregate<BaseShipDTO, Ship>(query, _shipsCollection);
return listResulted.FirstOrDefault();
}
and documents that i do tests on it in mongodb is as :
{
"_id": {
"$oid": "63d10256d3d1cc30603cfaf6"
},
"_t": "Speculator",
"Coordinates": {
"X": 12,
"Y": -4
},
"Health": 600,
"Max_Health": 100000,
"Name": "Roger",
"Creation_Date": {
"$date": {
"$numberLong": "1674136353103"
}
},
"Creatium_Cost": 300,
"Energy": 100,
"Max_Energy": 100,
"Next_Scan_Date": null,
"Planet_of_Arrival_Coordinate": {
"X": 13,
"Y": -4
},
"Scan_Cost": 5,
"Speed": 600,
"Next_Heal_Date": {
"$date": {
"$numberLong": "1675610925014"
}
},
"Arrival_Date": null,
"Owner_Id": {
"$numberLong": "279937954565193729"
}
}
so when i change the Health property for exemple, and after that i use this method :
public async Task UpdateAsync(Ship ship)
{
await _shipsCollection.ReplaceOneAsync(s => s._id == ship._id, ship, new ReplaceOptions { IsUpsert = false });
}
i see no change with my document in database except my Health field (and the Health Date, which is normal):
{
"_id": {
"$oid": "63d10256d3d1cc30603cfaf6"
},
"_t": "Speculator",
"Coordinates": {
"X": 12,
"Y": -4
},
"Health": 750,
"Max_Health": 100000,
"Name": "Roger",
"Creation_Date": {
"$date": {
"$numberLong": "1674136353103"
}
},
"Creatium_Cost": 300,
"Energy": 100,
"Max_Energy": 100,
"Next_Scan_Date": null,
"Planet_of_Arrival_Coordinate": {
"X": 13,
"Y": -4
},
"Scan_Cost": 5,
"Speed": 600,
"Next_Heal_Date": {
"$date": {
"$numberLong": "1675611313544"
}
},
"Arrival_Date": null,
"Owner_Id": {
"$numberLong": "279937954565193729"
}
}
But at this point, i get my firstly presented error around _t when i try to re get it using my getAsync method :/ despite the fact that the field '_t' dont change at all.
Thanks you for any help^, sorry for my weird english (i'm french huh) and sorry if i forget useful code parts !
error message after a get on a object who got a replaceOne before

I solved it by removing _t field in my bdd model :
I replace using a model with exact same fields wich my mongo db takes :
public record Ship(
ObjectId _id,
Coordinates? Coordinates,
int Health,
int Max_Health,
string Name,
DateTime Creation_Date,
int Creatium_Cost,
int Energy,
int Max_Energy,
DateTime? Next_Scan_Date,
Coordinates? Planet_of_Arrival_Coordinate,
int Scan_Cost,
string _t,
int Speed,
DateTime? Next_Heal_Date,
DateTime? Arrival_Date,
long? Owner_Id
);
i removed the _t field from it, it cwas causing a weird dual modification on it (on from mongo driver, on from my field)

Related

Registering GraphQL dynamic schema

I have a model class that allows users to specify the template which is used to create content with specified properties.
public class Model
{
public string Id { get; set; }
public string Alias { get; set; }
public ICollection<Field> Fields { get; set; }
}
public class Field
{
public FieldType Type { get; set; }
public string Alias { get; set; }
}
public enum FieldType
{
String = 1,
Email = 2,
Password = 3,
DateTime = 4,
Integer = 5,
Decimal = 6,
...
}
The content that is created based on this template will have the structure as below:
public class Entry
{
public string _id { get; set; }
public List<FieldValue> FieldValues { get; set; }
}
public class FieldValue
{
public object Value { get; set; }
public string Alias { get; set; }
public FieldType Type { get; set; }
}
So, I for example, can have data such as:
PersonModel
{
"id": "34752b15",
"alias": "person",
"fields": [
{
"type": 1,
"alias": "name"
},
{
"type": 2,
"alias": "email"
}
]
}
PersonEntries:
[
{
"_id": "426e",
"fieldValues": [
{
"alias": "name",
"value": "John",
"type": 1
},
{
"alias": "email",
"value": "john#stark.com",
"type": 2
}
]
},
{
"_id": "c6110fc3cc0e",
"fieldValues": [
{
"alias": "name",
"value": "Arya",
"type": 1
},
{
"alias": "email",
"value": "arya#stark.com",
"type": 2
}
]
}
]
Or:
ShapeModel
{
"id": "afd69af4",
"alias": "shape",
"fields": [
{
"type": 1,
"alias": "name"
},
{
"type": 6,
"alias": "area"
},
{
"type": 6,
"alias": "perimeter"
}
]
}
ShapeEntries:
[
{
"_id": "426e",
"fieldValues": [
{
"alias": "name",
"value": "my-square",
"type": 1
},
{
"alias": "area",
"value": 1,
"type": 6
},
{
"alias": "perimeter",
"value": 4,
"type": 6
}
]
},
{
"_id": "426enbv",
"fieldValues": [
{
"alias": "name",
"value": "my-triangle",
"type": 1
},
{
"alias": "area",
"value": 0.5,
"type": 6
},
{
"alias": "perimeter",
"value": 3,
"type": 6
}
]
}
]
and so on.
The idea is to create graphql schemas dynamically (on runtime) when a new model is created and allow users to query entries based on the model alias.
What I tried is:
public ISchema CreateEntrySchema(List<Entry> entries, Model model, IServiceCollection services)
{
var entryType = new ObjectGraphType() { Name = model.Alias };
entryType.Field("_id", new IdGraphType());
foreach (var field in model.Fields)
{
if (entryType.Fields.FirstOrDefault(f => f.Name == field.Alias) != null)
{
continue;
}
Type clrGraphType = field.Type.GetStandardType().GetGraphTypeFromType(isNullable: true);
IGraphType graphType = (IGraphType)Activator.CreateInstance(clrGraphType);
entryType.Field(field.Alias,
graphType,
resolve: context =>
{
var entry = (Entry)context.Source;
object firstOrDefault = entry?.FieldValues.FirstOrDefault(value => value.Alias == context.FieldDefinition.Name)?.Value;
return firstOrDefault;
});
}
var queryType = new ObjectGraphType();
queryType.Field(
model.Alias,
type: new ListGraphType(entryType),
arguments: new QueryArguments(ConstructArguments(model.Fields)),
resolve: context =>
{
List<KeyValuePair<string, ArgumentValue>> args = context.Arguments?.Where(pair => pair.Value.Value != null).ToList();
if (!args?.Any() ?? true)
{
return entries;
}
return args.Aggregate(entries, (current, pair) =>
current.Where(entry => entry.FieldValues.FirstOrDefault(field => field.Alias == pair.Key) != null && entry.FieldValues.FirstOrDefault(field => field.Alias == pair.Key).Value.Equals(pair.Value.Value))
.ToList());
});
ISchema schema = new Schema { Query = queryType };
schema.RegisterType(entryType);
services.AddGraphQL(a =>
{
a.AddSchema(schema).AddClrTypeMappings();
});
return schema;
}
The problem is that it is registering only the last schema. So, for example, if I will call this method like:
CreateEntrySchema(personEntries, personModel, services);
CreateEntrySchema(shapeEntries, shapeModel, services);
And query like this:
{
shape{
name
}
person{
name
}
}
The result is:
"GraphQL.Validation.Errors.FieldsOnCorrectTypeError: Cannot query field 'person' on type 'Object'. Did you mean 'shape'?",

C# - Remove duplicate objects using LINQ

I have below model classes
public class Hotel
{
public string hoteltype { get; set; }
public List<Room> rooms { get; set; }
}
public class Room
{
public Room2 room { get; set; }
public string name { get; set; }
}
public class Room2
{
public int number { get; set; }
public string category { get; set; }
public string subCategory { get; set; }
}
public class Root
{
public List<Hotel> hotels { get; set; }
}
Below is the JSON
{
"hotels": [
{
"hoteltype": "5star",
"rooms": [
{
"room": {
"number": 1,
"category": "Deluxe",
"subCategory": "type1"
},
"name": "xyz"
},
{
"room": {
"number": 2,
"category": "Deluxe",
"subCategory": "type2"
},
"name": "abc"
}
]
},
{
"hoteltype": "4star",
"rooms": [
{
"room": {
"number": 1,
"category": "Small",
"subCategory": "type1"
},
"name": "xyz"
},
{
"room": {
"number": 2,
"category": "Small",
"subCategory": "type4"
},
"name": "abc"
}
]
},
{
"hoteltype": "5star",
"rooms": [
{
"room": {
"number": 1,
"category": "Deluxe",
"subcategory": "type4"
},
"name": "xyz"
},
{
"room": {
"number": 2,
"category": "Deluxe",
"subcategory": "type5"
},
"name": "abc"
}
]
}
]
}
Expected Output:
{
"hotels": [
{
"hoteltype": "5star",
"rooms": [
{
"room": {
"number": 1,
"category": "Deluxe",
"subCategory": null
},
"name": "xyz"
},
{
"room": {
"number": 2,
"category": "Deluxe",
"subCategory": null
},
"name": "abc"
}
]
},
{
"hoteltype": "4star",
"rooms": [
{
"room": {
"number": 1,
"category": "Small",
"subCategory": null
},
"name": "xyz"
},
{
"room": {
"number": 2,
"category": "Small",
"subCategory": null
},
"name": "abc"
}
]
}
]
}
I'm trying to remove duplicates using LINQ - groupby and firstordefault. groupby should be on room - number and category but not on hoteltype. because we need combination of hoteltype, room number and category, if these three combinations are there in JSON that should be eliminated
Please suggest any solutions?
The Distinct() method exists entirely for this purpose.
You can either create a comparer or override Equals in Hotel, but I'll give an example with the latter.
public class Hotel : IEquatable<Hotel>
{
public string hoteltype { get; set; }
public List<Room> rooms { get; set; }
public bool Equals(Hotel other)
{
if (hoteltype != other.hoteltype) return false;
if (rooms.Length != other.rooms.Length) return false;
for (int i = 0; i < rooms.Length; i++)
{
if (!rooms[i].Equals(other.rooms[i]) return false;
}
return true;
}
}
You will also have to write an equatable override for the rooms.
public class Room : IEquatable<Room>
{
public Room2 room { get; set; }
public string name { get; set; }
public bool Equals(Room other)
{
return name == other.name &&;
room.Equals(other.room);
}
}
public class Room2 : IEquatable<Room2>
{
public int number { get; set; }
public string category { get; set; }
public string subCategory { get; set; }
public bool Equals(Room2 other)
{
return number == other.number &&;
category == other.category &&
subCategory == other.subCategory;
}
}
I'm trying to remove duplicates using LINQ - groupby and firstordefault. groupby should be on room - number and category but not on hoteltype. because we need combination of hoteltype, room number and category, if these three combinations are there in JSON that should be eliminated
From your question you require a Linq GroupBy on room => number, room => category .
var grp = rooms.GroupBy(
room => room.number,
room => room.category,
(rm_num, rm_cat) => new
{
num = rm_num,
cat = rm_cat
});
foreach(var result in grp) {
Console.WriteLine(result.num+" "+result.cat);
}
This might be off, but might I suggest you change the Datatype of your Enumeration to HashSet hotels? Hashsets cannot have duplicates.

Remove itens from JSON string based on a comparison between two JSON strings - C#

Given 2 JSON strings:
[
{
"id":"BA",
"description":"BrandA",
"values":[
{
"id":"CategoryA",
"description":"CategoryA"
},
{
"id":"CategoryB",
"description":"CategoryB"
},
{
"id":"CategoryC",
"description":"CategoryC"
},
{
"id":"CategoryD",
"description":"CategoryD"
},
{
"id":"CategoryE",
"description":"CategoryE"
},
{
"id":"CategoryF",
"description":"CategoryF"
},
{
"id":"CategoryG",
"description":"CategoryG"
},
{
"id":"CategoryH",
"description":"CategoryH"
}
]
},
{
"id":"BB",
"description":"BrandB",
"values":[
{
"id":"CategoryA",
"description":"CategoryA"
},
{
"id":"CategoryB",
"description":"CategoryB"
},
{
"id":"CategoryC",
"description":"CategoryC"
}
]
}
]
AND
[
{
"id":"BA",
"description":"BrandA",
"values":[
{
"id":"CategoryA",
"description":"CategoryA"
},
{
"id":"CategoryC",
"description":"CategoryC"
}
]
},
{
"id":"BB",
"description":"BrandB",
"values":[
{
"id":"CategoryB",
"description":"CategoryB"
}
]
}
]
First one is the original. The second are the values that I want to remove from the original. So basically, if there is a match on brand and category between first and second JSON, regardless of the order of the elements, I want that match to be removed.
The expected result would be someting like this:
[
{
"id":"BA",
"description":"BrandA",
"values":[
{
"id":"CategoryB",
"description":"CategoryB"
},
{
"id":"CategoryD",
"description":"CategoryD"
},
{
"id":"CategoryE",
"description":"CategoryE"
},
{
"id":"CategoryF",
"description":"CategoryF"
},
{
"id":"CategoryG",
"description":"CategoryG"
},
{
"id":"CategoryH",
"description":"CategoryH"
}
]
},
{
"id":"BB",
"description":"BrandB",
"values":[
{
"id":"CategoryA",
"description":"CategoryA"
},
{
"id":"CategoryC",
"description":"CategoryC"
}
]
}
]
Catagory A and C in Brand A were removed as well as Category B in Brand B.
Based in some research, I was using https://github.com/wbish/jsondiffpatch.net, tried to work with it's functions, but so far I didn't manage to achieve the result I want. Also, to solve this by processing JSON direcly is not a must. If there is a simpler solution to achieve that by converting them to lists and use something like LINQ for example, it works for me as well (tried that, but didn't manage to find a way to do this comparison).
Thanks in advance.
If performance does not matter, the JsonSerializer and LINQ can be used:
Model
public class JsonModel
{
public class ValueModel
{
public string Id { get; set; }
public string Description { get; set; }
}
public string Id { get; set; }
public string Description { get; set; }
public IEnumerable<ValueModel> Values { get; set; }
}
Deserialize and LINQ
string json1Str = #"[...]";
string json2Str = #"[...]";
var opt = new System.Text.Json.JsonSerializerOptions { PropertyNameCaseInsensitive = true };
var json1 = System.Text.Json.JsonSerializer.Deserialize<List<JsonModel>>(json1Str, opt);
var json2 = System.Text.Json.JsonSerializer.Deserialize<List<JsonModel>>(json2Str, opt);
var result = json1.
Join(json2, j1 => j1.Id, j2 => j2.Id, (j1, j2) => new JsonModel
{
Id = j1.Id,
Description = j1.Description,
Values = j1.Values.Where(j1 => !j2.Values.Select(val => val.Id).Contains(j1.Id))
});
Console.WriteLine(System.Text.Json.JsonSerializer.Serialize(result, new System.Text.Json.JsonSerializerOptions { WriteIndented = true }));
}
Result
[
{
"Id": "BA",
"Description": "BrandA",
"Values": [
{
"Id": "CategoryB",
"Description": "CategoryB"
},
{
"Id": "CategoryD",
"Description": "CategoryD"
},
{
"Id": "CategoryE",
"Description": "CategoryE"
},
{
"Id": "CategoryF",
"Description": "CategoryF"
},
{
"Id": "CategoryG",
"Description": "CategoryG"
},
{
"Id": "CategoryH",
"Description": "CategoryH"
}
]
},
{
"Id": "BB",
"Description": "BrandB",
"Values": [
{
"Id": "CategoryA",
"Description": "CategoryA"
},
{
"Id": "CategoryC",
"Description": "CategoryC"
}
]
}
]

Problems deserializing Newtonsoft JSON in c# returning null

I'm trying to deserialize a json in c# with Newtonsoft, but when i try to print the elements, it returns null.
The json is the following:
{
"data": [
{
"ufs": [
{
"delivery": [
{
"grade": "100",
"name": "P01",
"id": 10,
"status": "submitted"
},
{
"name": "P02",
"id": 11,
"status": "new"
}
],
"name": "UF1",
"id": "18"
},
{
"delivery": [
{
"name": "P03",
"id": 12,
"status": "new"
},
{
"name": "P04",
"id": 13,
"status": "new"
}
],
"name": "UF2",
"id": "19"
}
],
"name": "M1",
"id": "5"
},
{
"ufs": [
{
"delivery": [
{
"name": "P01",
"id": 6,
"status": "submitted"
},
{
"name": "P02",
"id": 7,
"status": "new"
}
],
"name": "UF1",
"id": "23"
},
{
"delivery": [
{
"name": "P03",
"id": 8,
"status": "new"
},
{
"name": "P04",
"id": 9,
"status": "new"
}
],
"name": "UF2",
"id": "24"
}
],
"name": "M2",
"id": "6"
}
]
}
So, having this JSON, i went to this site to generate the classes i would need, that are the following ones:
public class Delivery
{
public string grade { get; set; }
public string name { get; set; }
public int id { get; set; }
public string status { get; set; }
}
public class Uf
{
public List<Delivery> delivery { get; set; }
public string name { get; set; }
public string id { get; set; }
}
public class Root
{
public List<Uf> ufs { get; set; }
public string name { get; set; }
public string id { get; set; }
}
So finally, when i deserialize the JSON with this line
List<Root> myDeserializedClass = JsonConvert.DeserializeObject<List<Root>>(json);
And try to print
foreach (Root item in myDeserializedClass)
{
Console.WriteLine(item.ufs.Count);
}
It says "Root.ufs.get returned null."
Any clue of where im mistaking? Thanks for the help!
Grettings from Spain!
You class structure would be like this
public class Delivery
{
public string grade { get; set; }
public string name { get; set; }
public int id { get; set; }
public string status { get; set; }
}
public class Uf
{
public List<Delivery> delivery { get; set; }
public string name { get; set; }
public string id { get; set; }
}
public class Data
{
public List<Uf> ufs { get; set; }
public string name { get; set; }
public string id { get; set; }
}
public class Root
{
public List<Data> data { get; set; }
}
When you needed to deserialize the Json you will do like this
Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(json);
Here is the json that I used
string json = #"{'data': [
{
'ufs': [
{
'delivery': [
{
'grade': '100',
'name': 'P01',
'id': 10,
'status': 'submitted'
},
{
'name': 'P02',
'id': 11,
'status': 'new'
}
],
'name': 'UF1',
'id': '18'
},
{
'delivery': [
{
'name': 'P03',
'id': 12,
'status': 'new'
},
{
'name': 'P04',
'id': 13,
'status': 'new'
}
],
'name': 'UF2',
'id': '19'
}
],
'name': 'M1',
'id': '5'
},
{
'ufs': [
{
'delivery': [
{
'name': 'P01',
'id': 6,
'status': 'submitted'
},
{
'name': 'P02',
'id': 7,
'status': 'new'
}
],
'name': 'UF1',
'id': '23'
},
{
'delivery': [
{
'name': 'P03',
'id': 8,
'status': 'new'
},
{
'name': 'P04',
'id': 9,
'status': 'new'
}
],
'name': 'UF2',
'id': '24'
}
],
'name': 'M2',
'id': '6'
}
]
}";

C# JSON.net DeserializeObject<Class> fills up a with null

Having some problems deserializing JSON in JSON.net.
First of all I am pulling JSON from my source that looks like the following.
{
"guest": {
"id": 11111,
"A": "bla",
"B": "bla",
"C": false,
"credentials": [
{
"id": 222,
"Z": "bla",
"accounts": [
{
"id": 01,
"type": "bla"
}
]
},
{
"id": 222,
"Z": "bla",
"accounts": [
{
"id": 02,
"type": "bla"
}
]
},
{
"id": 333,
"Z": "bla",
"accounts": [
{
"id": 03,
"type": "bla"
},
{
"id": 04,
"type": "bla"
},
{
"id": 05,
"type": "bla"
},
]
},
]
}
}
Within my code I have the following classes
public class guest
{
public int id { get; set; }
public string A { get; set; }
public string B { get; set; }
public bool C { get; set; }
public IList<credentials> credentials { get; set; }
}
public class credentials
{
public int id { get; set; }
public string Z { get; set; }
public IList<accounts> accounts { get; set; }
}
public class accounts
{
public int id { get; set; }
public string type { get; set; }
}
From this point I get my JSON from an HttpWebResponse and deserialize.
var httpResponseGetResponse = (HttpWebResponse)httpWebRequestGetResponse.GetResponse();
using (var streamReader = new StreamReader(httpResponseGetResponse.GetResponseStream(), Encoding.UTF8))
{
var result = streamReader.ReadToEnd();
guest deseriazedJSON = JsonConvert.DeserializeObject<guest>(result);
}
This ends with everything being NULL. Am I blind and missing something in the JSON.net docs?
Appreciate any help and thank you in advance.
You have an object with a single property named guest on a root level of your JSON. So it can be deserialized in next scenario:
public class Response
{
public guest guest { get; set; }
}
...
var httpResponseGetResponse = (HttpWebResponse)httpWebRequestGetResponse.GetResponse();
using (var streamReader = new StreamReader(httpResponseGetResponse.GetResponseStream(), Encoding.UTF8))
{
var result = streamReader.ReadToEnd();
var deseriazedJSON = JsonConvert.DeserializeObject<Response>(result);
}
It's better to change your JSON input to avoid an extra wrapper:
{
"id": 11111,
"A": "bla",
"B": "bla",
"C": false,
"credentials": [
{
"id": 222,
"Z": "bla"
"accounts": [
{
"id": 01,
"type": "bla"
}
]
},
{
"id": 222,
"Z": "bla"
"accounts": [
{
"id": 02,
"type": "bla"
}
]
},
{
"id": 333,
"Z": "bla"
"accounts": [
{
"id": 03,
"type": "bla"
},
{
"id": 04,
"type": "bla"
},
{
"id": 05,
"type": "bla"
},
]
},
]
}

Categories

Resources