Getting A List From Service Async - c#

While trying to get list from an url, program stops and throw an exception like that
An exception of type 'System.AggregateException' occurred in mscorlib.dll but was not handled in user code
also
Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.IEnumerable`1[WebAPIDemo.Models.Person]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.
Path 'Message', line 1, position 11.
I thought its because of using IEnumerable<MyObject> in my program but when I use only MyObject it goes away from this point but it crush into somewhere else.
I'm stuck now.
Here is my code:
CONTROLLER.CS:
private IEnumerable<Person> CallPersonListServiceAsync(HttpClient ins, string url)
{
var content = ins.GetAsync(url).Result.Content;
var personsList = content.ReadAsAsync(typeof(IEnumerable<Person>)).Result as IEnumerable<Person>;
return personsList;
}
PERSON.CS:
public class Person
{
public string name { get; set; }
public string surname { get; set; }
public DateTime dob { get; set; }
}
Is it really happening that because I'm using IEnumerable or something different. Thanks

The error is telling you that the JSON you're receiving is an object, not a collection. So you have to deserialize it to an object, not a collection. Unless the JSON is very different from what you expect (that is, not a Person at all) then you would simply deserialize it to a Person:
var result = content.ReadAsAsync(typeof(Person)).Result as Person;
Which would of course necessitate changing the return type (and name) of your method:
private Person CallPersonServiceAsync(HttpClient ins, string url)
Alternatively, instead of changing the method signature you could manufacture a list from that single person and return that:
return new List<Person> { result };
Additionally, the async nature of your code is very broken. For one thing, you are calling .Result explicitly which is almost always the wrong approach. Second, your method's name advertises it as an async method but it's not async at all.
You can correct both of these problems by making use of async and await:
private async Task<Person> CallPersonServiceAsync(HttpClient ins, string url)
{
var content = (await ins.GetAsync(url)).Content;
var result = (await content.ReadAsAsync(typeof(Person))) as IEnumerable<Person>;
return result;
}

Related

safe Serialize and Deserialize with Newtonsoft.Json

I have a code that takes messages of any type and serialize them into the DB, while saving the type of the message and the serialized json string.
I have a side process that should deserialize the messages later on and send them to the queue.
To perform the serialization and deserialization I use JsonConvert of Newtonsoft.Json:
For deserialization I use the following method:
object? DeserializeObject(string value, Type type)
For serialization I use the following method:
string SerializeObject(object? value)
I have the following questions:
A. I saw that in case DeserializeObject receives a wrong type name it still deserialize the object but his type is Newtonsoft.Json.Linq.JObject and not the type I passed into the method, I expected it will throw an exception, this behavior is very bad for us, is there any way to cause the deserialize to throw exception in this scenario?
B. Is the code below secured? I saw that the library has variabilities such as depicted here
private void StackOverflowQuestion()
{
Bus.Employees.Messages.LevelCreated levelCreated = new Bus.Employees.Messages.LevelCreated
{
Name = "director",
};
//var messageType = levelCreated.GetType().AssemblyQualifiedName;
string messageData = JsonConvert.SerializeObject(levelCreated);
//Deserialize with type that is not correct
object deserializeMessaged = DeserializeMessage("my cool type which does not exists!", messageData);
string theType = deserializeMessaged.GetType().FullName;//theType = Newtonsoft.Json.Linq.JObject
}
private object DeserializeMessage(string messageType, string messageSerializedData)
{
Type type = Type.GetType(messageType);
return JsonConvert.DeserializeObject(value: messageSerializedData, type);
}

Json array exception

I create a Json file and insert some objects of my class inside it, like this:
private async void Save_Clicked(object sender, EventArgs e)
{
Note NoteNew = new Note
{
FraseGiorno = obj1.FraseGiornaliera,
Nota = TestoNota.Text,
Data= DateTime.Today.ToString().Remove(10,9),
};
File.WriteAllText(NotesFile, JsonConvert.SerializeObject(NoteNew));
}
Then when I try to read the file and deserialize the json I get this exception. how could i solve?
string NotesFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Note.json");
ObservableCollection<Note> listNote = new ObservableCollection<Note>();
FraseClass obj1;
public NotePage(FraseClass obj1)
{
InitializeComponent();
this.obj1 = obj1;
if (File.Exists(NotesFile))
{
listNote = JsonConvert.DeserializeObject<ObservableCollection<Note>>(File.ReadAllText(NotesFile));
CollectionNote.ItemsSource = listNote;
}
}
Newtonsoft.Json.JsonSerializationException: 'Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.ObjectModel.ObservableCollection`1[MotiVApp.NotePage+Note]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.
Path 'FraseGiorno', line 1, position 15.'
I don't understand why the exception refers to the 'FraseGiorno' property
You are serializing an object into the file, but deserializing into a collection.
If you absolutely must use an ObservableCollection, separate the initialization and deserialization steps:
var note = JsonConvert.DeserializeObject<Note>(File.ReadAllText(NotesFile));
listNode.Add(note);
CollectionNote.ItemsSource = listNote;

How to remove a child from System.Object object?

At a Rest-API I got an incoming object from Type System.Object.
public async Task<IActionResult> UploadFileRegistration([FromBody]object incomingObject)
This object I would like to parse into my type.
public class MyType
{
public string name;
public double age;
}
The incoming object can has one more attribute "version" and the content of version can look different each time.
{"name":"Gisela", "age":29.64}
{"name":"Gisela", "age":29.64, "version":"new"}
{"name":"Gisela", "age":29.64, "version":2.0}
{"name":"Gisela", "age":29.64, "version":["param1":17,"param2":"oho"]}
{"name":"Gisela", "age":29.64, "version":true}
In case this object has a child with name "version". I want to remove this child and put it into a string. In the parent object the child should be removed.
How to do this?
I think of some thing what do's that (made-up code)..
private object o;
private string myVersion; //...
if(o.HasChild("version"))
{
myVersion = o.Child("version");
o.DeleteChild("version");
}
Instead of a system.object, I would try using a Newtonsoft.Json.Linq.JObject
I'm not sure if you need to declare your parameter as dynamic or if JObject will work correctly.
Here is an article that describes it. (It is likely out-dated, but somewhere to start.)
Using JSON.NET for dynamic JSON parsing

What signature for a method returning json?

What is the appropriate signature for a method that is returning a json object in a console app?
I can return a list of employees with a method doing the following:
public List<Employee> GetListOfEmployees();
What should the signature of my method be if I wand the same list to be returned as JSON?
JSON isn't a class in C#. It's a standard format for data serialization. You'd either return an object to be serialized by consuming code:
public List<Employee> GetListOfEmployees()
{
// return a List<Employee>
}
Or return a string representing the serialized object:
public string GetListOfEmployees()
{
// serialize a List<Employee> to a string and return the string
}
As for how to serialize the object, there are a variety of ways to do that. You could even return a string literal that you manually wrote which represents the object, it makes no difference to the consuming code as long as it's valid JSON.

JSon.NET deserializing object doesn't work

So I have a Client-Server application that is using this class for communication, it contains an object so I can send any kind of data between server and client:
public class comObj
{
public eDisconnectedReason dcReason;
public object payload;
}
Before sending it through the Socket I will serialize it using JSon.Net, e.g.:
string jsonString = JsonConvert.SerializeObject((new Common.comObj() { dcReason = Server.disconnectedReason, payload = Data }), Formatting.None);
now the server receives exactly the string that was sent by the client:
sent string: "{\"dcReason\":4,\"payload\":{\"msg\":\"hi\"}}"
received string: "{\"dcReason\":4,\"payload\":{\"msg\":\"hi\"}}"
however when I try to deserialize the received string into the original comObj:
Common.comObj rcvdObj = JsonConvert.DeserializeObject<Common.comObj>(rcvdString);
rcvdObj.payload is of type Newtonsoft.Json.Linq.JObject instead of object.
Let us start by considering your JSON input:
{
"dcReason": 4,
"payload": {
"msg": "hi"
}
}
Using Json.NET you have two key ways of deserializing JSON data. You can:
Deserialize it into a specific concrete type
You can deserialize it into the generic JToken type. (In your case, it instantiates a JObject -- a subclass of JToken -- because JSON.Net recognized that the JSON input specified an object, as opposed to a primitive type or an array)
In your case, you actually ended up with a hybrid of both approaches. Since you specified a specific type for the root object, it returned an instance of comObj. Since you merely specified object as the type of the property payload, Json.NET did its best and simply reverted to option 2) and gave you an instance of JObject, which contains the data such as msg.
You have two options to solve your problem. You can:
Interrogate the payload property as a JObject, like you would have had to do for the entire JSON body if you had not used option 1).
Define a concrete type to represent the payload property. I strongly recommend this approach, as it is considerably more typesafe and also easier to work with.
To achieve the former, you can use faclities such as o["msg"] -- essentially like a dictionary.
To achieve the latter -- which I would recommmend -- simply define a type for payload. In other words, change you code to:
public class comObj
{
public eDisconnectedReason dcReason;
public Payload payload;
}
public class Payload
{
public string msg { get; set; }
}
Now when you deserialize your JSON, you'll be able to use the syntax:
Console.WriteLine(rcvdObj.payload.msg);
And -- importantly -- if you later decide to rename msg in your JSON payload to, say, message you will be able to properly refactor the property msg of payload to message and expect all usages to be fixed. This is obviously less robust when using strings.

Categories

Resources