Here is the sample data from a collection. Basically the only thing that I am trying to do is read all of the data like this in as a "Student" but it is throwing an error for some reason. It works fine when I read them all in as Bson documents but that is not what I want to do. Here is the error:
An unhandled exception of type 'System.AggregateException' occurred in mscorlib.dll
Additional information: One or more errors occurred.
what am I doing wrong?
{
"_id" : 137,
"name" : "Tamika Schildgen",
"scores" : [
{
"type" : "exam",
"score" : 4.433956226109692
},
{
"type" : "quiz",
"score" : 65.50313785402548
},
{
"type" : "homework",
"score" : 89.5950384993947
}
]
}
static async Task MainAsync(string[] args)
{
var client = new MongoClient();
var db = client.GetDatabase("school");
var col = db.GetCollection<Student>("students");
var list = await col.Find(new BsonDocument())
.ToListAsync();
foreach(var doc in list)
{
Console.WriteLine(doc);
}
}
}
class Student
{
public ObjectId Id { get; set; }
public string name { get; set; }
public Scores[] scores { get; set; }
}
class Scores
{
public string type { get; set; }
public double score { get; set; }
}
The error lies in Id field type:
If you turn on the option of breaking execution when a CLR exception is thrown (Menu Debug|Exceptions), you will see a message similar to: "An error occurred while deserializing the Id property of class ConsoleApplication2.Student: Cannot deserialize a 'ObjectId' from BsonType 'Double'."
If you change the class Student to:
public class Student
{
public int Id { get; set; }
public string name { get; set; }
public Scores[] scores { get; set; }
}
the exception will not be thrown anymore.
(Additionally, to get readable results, you should probably override ToString() method for Student class).
Related
I am trying to fetch data from inside mongodb.
I am getting the following exception:
System.TypeInitializationException: 'The type initializer for 'MongoDB.Bson.Serialization.BsonClassMap' threw an exception.'
ArgumentNullException: Value cannot be null. Arg_ParamName_Name
public IQueryable<IssueDto> FetchCollection(string databaseName, string collectionName)
{
var dbClient =
new MongoClient("mongo connection string here");
var database = dbClient.GetDatabase(databaseName);
var collection = database.GetCollection<IssueDto>(collectionName);
return collection.AsQueryable();
}
Json inside mongo:
{
"_id":{"$oid":"63920bcf14ab25ab93444804"},
"name":"This is a task",
"completed": true,
"issueId":1234
}
The model class is as follows:
public class IssueDto
{
[BsonElement("_id")]
public ObjectId Id { get; set; }
[BsonElement("issueId")]
public int IssueId { get; set; }
[BsonElement("name")]
public string Name { get; set; }
[BsonElement("completed")]
public bool Completed { get; set; }
}
Can anyone spot what is going wrong?
Other info: .NET6, MongoDB.Driver 2.8.0
I am trying to retrieve data from local MongoDb with JSON documents like this:
{
"teryt_num_code" : "AB",
"id": 1,
"name": "Alabama"
}
I have created a POCO class as following:
public class Sensor
{
public int id { get; set; }
public string name { get; set; }
public string teryt_num_code { get; set; }
}
To retrieve all data from my database I use a method below:
public async Task<ICollection<Sensor>> GetAllAsync() => await _collection.Find(_ => true).ToListAsync();
but the exception was thrown calling that method:
An error occurred while deserializing the property of class Sensor:
Element 'id' does not match any field or property of class Sensor.
What I am doing wrong?
By default, the id property of your class is mapped to the BSON id (property _id on the document). This leaves the id property in the MongoDB document without a corresponding property in the POCO. Therefore, the error is raised.
In order to fix the deserialization error, you can apply both a BsonNoId and a BsonIgnoreExtraElements attribute to the POCO:
[BsonNoId]
[BsonIgnoreExtraElements]
public class Sensor
{
public int id { get; set; }
public string name { get; set; }
public string teryt_num_code { get; set; }
}
BsonNoId disables the convention; therefore BSON id is mapped to POCO id. BsonIgnoreExtraElements fixes the error that the driver does not know how to deserialize the _id property that every MongoDB document contains.
I have this JSON response that is produced from a POST request that I have sent.
{
"correlationID": "00000000-0000-0000-0000-000000000000",
"scenarioID": 2,
"scenarioIsAcceptedInPrinciple": false,
"valid": false,
"errors": [
{
"errorID": 90,
"errorText": "For the 1st Employment of the 1st Applicant Please provide a valid Landline"
},
{
"errorID": 22,
"errorText": "The provided value 'string' is not a valid value for the property 'applicants[0][email]'"
}
]
}
I would like to deserialize it so I can get the errorID and errorText and do testing assertions to see if the correct error ID and text came back.
I have got it to work with:
public partial class postRequest
{
public bool Valid { get; set; }
public object Errors { get; set; }
}
and it returns all of the error, like this:
Standard Output:
[
{
"errorID": 90,
"errorText": "For the 1st Employment of the 1st Applicant Please provide a valid Landline"
},
{
"errorID": 22,
"errorText": "The provided value 'string' is not a valid value for the property 'applicants[0][email]'"
}
]
How would I return just the error ID and error text?
Thanks
You should create another class for the error.
public class Error
{
public string ErrorID { get; set; }
public string ErrorText { get; set; }
}
And then use that in the other class:
public Error[] Errors { get; set; }
Finally you access the errors like:
response.Errors[0].ErrorID
You have to deserialize it like this object :
public class JsonResponse
{
public bool valid { get; set; }
public List<Error> errors { get; set; }
}
public class Error
{
public int errorID { get; set; }
public string errorText { get; set; }
}
For deserialization:
var data =System.Text.Json.JsonSerializer.Deserialize<JsonResponse>("your json source");
you have a list of errors, not just a one
List<Error> errors = JObject.Parse(json)["errors"].Select(x => x.ToObject<Error>()).ToList();
public class Error
{
public int ErrorID { get; set; }
public string ErrorText { get; set; }
}
you can see them
foreach (var error in errors)
{
Console.WriteLine($"Error Id : {error.ErrorID}, Error Text {error.ErrorText}");
}
// or
var errId=errors[0].ErrorID;
I have to work with an API which handles error responses like this:
{
"error": {
"code": 3,
"message": "error message"
}
}
And success respones like this:
{
"data": {
"key": "value"
}
}
Error respones will always contain a code (integer) and a message (string), where as success respones can be different a lot ranging from just a few key-value-pairs to many objects and arrays.
I have created classes for every success "data" section and I can parse them successfully. Now I struggle with the simple part to determine if the response I got is actually an error or a success response.
My Idea was to create these classes:
public class APIResponse
{
[JsonProperty("error")]
public APIResponseError Error { get; set; }
[JsonProperty("data")]
public string Data { get; set; }
}
public class APIResponseError
{
[JsonProperty("code")]
public int Error { get; set; }
[JsonProperty("message")]
public string Message { get; set; }
}
And to serialize to the class APIResponse. This works only for error responses (kinda obvious) as the data responses are more than just a string which the APIResponse.Data actually is. My idea was to not deserialize the data field and just store it as a string in APIResponse.Data. Then, when I check and see that error is null, I would deserialize the APIResponse.Data property with the correct class. But how can I do this?
You can set type of Data property to JToken:
public class APIResponse
{
[JsonProperty("error")]
public APIResponseError Error { get; set; }
[JsonProperty("data")]
public JToken Data { get; set; }
}
And deserialize later with ToObject:
myCorrectResponse.Data.ToObject<ExpectedDataType>()
But I highly doubt that you will be sent any data in case of error response so I would recommend making APIResponse generic (where T could be object, array, etc.):
public class APIResponse<T>
{
[JsonProperty("error")]
public APIResponseError Error { get; set; }
[JsonProperty("data")]
public T Data { get; set; }
}
Which, in case of your example json will be used for example like:
class MyClass
{
[JsonProperty("key")]
public string Key { get; set; }
}
JsonConvert.DeserializeObject<APIResponse<MyClass>>(json);
After a deserialization I save the content in an object:
var obj = JsonConvert.DeserializeObject<dynamic>(responseText);
so I execute a loop for populate a DataGrid
foreach(var item in obj)
{
MainWindow.AppWindow.Squadre_DataGrid.Items.Add(new Teams.Club_Information
{
code = item.code,
name = item.name,
shortName = item.shortName,
squadMarketValue = item.squadMarketValue
});
}
The problem's that inside the foreach the compiler show Runtime Binder Exception.
Why happean this?
Some more details:
Class structure
public class Self
{
public string href { get; set; }
}
public class Fixtures
{
public string href { get; set; }
}
public class Players
{
public string href { get; set; }
}
public class Links
{
public Self self { get; set; }
public Fixtures fixtures { get; set; }
public Players players { get; set; }
}
public class RootObject
{
public Links _links { get; set; }
public string name { get; set; }
public string code { get; set; }
public string shortName { get; set; }
public string squadMarketValue { get; set; }
public string crestUrl { get; set; }
}
JSON structure:
{
"_links": {
"self": { "href": "http://api.football-data.org/alpha/teams/19" },
"fixtures": { "href": "http://api.football-data.org/alpha/teams/19/fixtures" },
"players": { "href": "http://api.football-data.org/alpha/teams/19/players" }
},
"name": "Eintracht Frankfurt",
"code": "SGE",
"shortName": "Eintr. Frankfurt",
"squadMarketValue": "75.475.000 ?",
"crestUrl": "http://upload.wikimedia.org/wikipedia/commons/0/04/Eintracht_Frankfurt_Logo.svg"
}
The object you are deserializing does not contain a property named code. So the line code = item.code causes an exception at runtime, because the Json.Net object behind the dynamic does not contain a value named code.
This means that the Json that you are parsing does not contain a property named code. Or else it only sometimes contains a property named code. In that case you'll have to either parse it is a JObject and check if the property exists or create an type do deserialize it into.'
Edit
Based on the Json that you posted along with the class structure it looks like you should just be deserializing directly into a RootObject class:
var obj = JsonConvert.DeserializeObject<RootObject>(responseText);
Or in any case you can still deserialize into a dynamic but you need to get rid of the foreach since you don't have a collection of RootObject
var obj = JsonConvert.DeserializeObject<dynamic>(responseText);
MainWindow.AppWindow.Squadre_DataGrid.Items.Add(new Teams.Club_Information
{
code = obj.code,
name = obj.name,
shortName = obj.shortName,
squadMarketValue = obj.squadMarketValue
});
Where you went wrong was the foreach. Since obj is dynamic there is no compiler error and the Json.Net JObject that is returned supports iteraction. But the that gives you back each of the property values, (e.g. _links, name, etc) on at a time, not the object that you are interested in.