JSON not deserializing some values - c#

I’ve got a base class (which is used a base for a User class):
public abstract class UserB2C
{
…
public List<SignInName> SignInNames { get; set; }
…
}
public class SignInName
{
string Type { get; set; }
string Value { get; set; }
}
And some JSON which includes:
\"signInNames\":[{\"type\":\"emailAddress\",\"value\":\"user#yahoo.co.uk\"}],
which is passed to:
JsonConvert.DeserializeObject<User>(json);
But the object created (deserialised) has:
"signInNames": [
{}
],
Any ideas why the field doesn’t get populated?
There is no error generated.
All other (simple) values get populated ok.
I've tried changing the case of Type and Value to match the JSON string,
and also tried explicitly creating the List<SignInName> when the object is created, but to no avail.

Properties of SignInName class should be declared as public in order to be deserialized with values.
public class SignInName
{
public string Type { get; set; }
public string Value { get; set; }
}
UPDATE
Here is a Minimal, Complete, and Verifiable example:
using Newtonsoft.Json;
using System.Collections.Generic;
class Program
{
static void Main(string[] args)
{
var json =
"{\"signInNames\":[{\"type\":\"emailAddress\",\"value\":\"user#example.com\"}]}";
var user = JsonConvert.DeserializeObject<User>(json);
System.Console.WriteLine(JsonConvert.SerializeObject(user));
}
}
public abstract class UserB2C
{
public List<SignInName> SignInNames { get; set; }
}
public class User : UserB2C { }
public class SignInName
{
string Type { get; set; }
string Value { get; set; }
}
Output is {"SignInNames":[{}]}
If we make SignInName class properies public the output will be:
{"SignInNames":[{"Type":"emailAddress","Value":"user#example.com"}]}

Related

Trying to deserialize JSON returns null values

Using the method JsonConvert.DeserializeObject returns the default values for all properties.
var current = JsonConvert.DeserializeObject<Current>(myJson);
{
"location": {
"name": "London"
},
"current": {
"temp_c": 5.0,
"cloud": 50
}
}
public class Current
{
public double Temp_c { get; set; }
public double Cloud { get; set; }
}
The expected current object should have the values: 50 for Cloud, and 5.0 for Temp_c, but returns the default values for all properties.
You need to define a class model like json object
and then deserialize to it
public class YourModel {
//create location class that has Name property
public Location Location { get; set; }
//create current class that has Temp_c and Cloud property
public Current Current { get; set; }
}
and then
var data = JsonConvert.DeserializeObject<YourModel>(myJson);
and get the current value from data object
var current = data.Current;
your 'Current' class is far of been like the JSON you post.
You need to convert the JSON string to a C# class. You can use QuickType to convert it (Newtonsoft compatible).
Note: I am using System.Text.Json.Serialization but the class model should be equal, just change:
[JsonPropertyName("temp_c")] // .Net serializer (I prefer this)
to
[JsonProperty("temp_c")] // Newtonsoft.Json serializer
(replace "temp_c" for every name)
Here is the class model (a complete console application) you need:
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
#nullable disable
namespace test
{
public class Weather
{
[JsonPropertyName("location")]
public Location Location { get; set; }
[JsonPropertyName("current")]
public Current Current { get; set; }
}
public class Location
{
[JsonPropertyName("name")]
public string Name { get; set; }
}
public class Current
{
[JsonPropertyName("temp_c")]
public double TempC { get; set; }
[JsonPropertyName("cloud")]
public int Cloud { get; set; }
}
class Program
{
static void Main(string[] args)
{
string json = "{\"location\": { \"name\": \"London\" }, \"current\": { \"temp_c\": 5.0, \"cloud\": 50 }}";
Weather myWeather = JsonSerializer.Deserialize<Weather>(json);
Console.WriteLine("Location: {0} - Temp: {1:F}", myWeather.Location.Name, myWeather.Current.TempC);
}
}
}
Now the Deserializer will work OK.

How can I ignore the property name that I use in the jsonproperty attribute, provided that it is only once

My problem is that I deserialize the incoming data and transfer it to this class using jsonproperty. but I don't want to use property name attribute that I use in jsonproperty while serializing.
example class
public class DocumentDetail
{
[JsonProperty("KAREKOD")]
public string qrCode { get; set; }
[JsonProperty("GTIN")]
public string gtinNumber { get; set; }
[JsonProperty("LOTNUMBER")]
public string lotNumber { get; set; }
}
example serialize
{
DocumentDetail docDetail=new DocumentDetail(){qrCode="123456adsfg789",gtinNumber ="123asdf548654",lotNumber ="1231231sdfg23"};
var obj=JsonConvert.SerializeObject(body);
}
example result
{
"qrCode" : "123456adsfg789",
"gtinNumber" : "123asdf548654",
"lotNumber" : "1231231sdfg23"
}
you can add a constructor to your class
public class DocumentDetail
{
public string qrCode { get; set; }
public string gtinNumber { get; set; }
[JsonProperty("lotNumber")] // optional, you can assign any name for serialization
public string lotNumber { get; set; }
[Newtonsoft.Json.JsonConstructor]
public DocumentDetail( string KAREKOD,string GTIN, string LOTNUMBER)
{
qrCode=KAREKOD;
gtinNumber=GTIN;
lotNumber=LOTNUMBER;
}
public DocumentDetail() {}
}
and you don't need to include all properties in the constructor, just include the properties that need different names for a serialization and a deserialiazation.
This worked for me
public class Foo
{
private string bar;
public string IncomingBar { set { bar = value; } }
public string OutgoingBar { get { return bar; } }
}

Json class saving a value while containing other default values

Hey all I am trying to figure out how to go about saving just one value in my JSON class instead of having to write the whole JSON out again with "New". I am using the Newton JSON.Net.
This is my JSON structure:
public class GV
{
public class Data
{
[JsonProperty("pathForNESPosters")]
public static string PathForNESPosters { get; set; }
[JsonProperty("pathForSNESPosters")]
public static string PathForSNESPosters { get; set; }
[JsonProperty("pathForSEGAPosters")]
public static string PathForSEGAPosters { get; set; }
[JsonProperty("pathToNESContent")]
public static string PathToNESContent { get; set; }
[JsonProperty("pathToSNESContent")]
public static string PathToSNESContent { get; set; }
[JsonProperty("pathToSEGAContent")]
public static string PathToSEGAContent { get; set; }
[JsonProperty("lastSavedVolume")]
public static double LastSavedVolume { get; set; }
}
public class Root
{
public Data data { get; set; }
}
And I have no issues with loading that data from a file into my class:
GV.Root myDeserializedClass = JsonConvert.DeserializeObject<GV.Root>(File.ReadAllText(
currentAssemblyPath + String.Format(#"\Resources\{0}", "dataForLinks.json")
));
But I have yet to find anything searching that will let me do one update to an object in the class without wiping it out doing a New statement.
What I am wanting to do is something like the following:
-Load the json into my class object [Done]
-Save a value thats in my class object [stuck here]
GV.pathToNESContent = "new value here";
-Save class object (with the one new value) back to the file for which it came from preserving the other original values. [not here yet]
When I update just that one class object I am wanting to contain the original values for all the other JSON data I read in from the file.
Anyone have a good example of the above you can share?
update
I'd ditch the inner class structure:
namespace GV
{
public class Data
{
[JsonProperty("pathForNESPosters")]
public string PathForNESPosters { get; set; }
[JsonProperty("pathForSNESPosters")]
public string PathForSNESPosters { get; set; }
[JsonProperty("pathForSEGAPosters")]
public string PathForSEGAPosters { get; set; }
[JsonProperty("pathToNESContent")]
public string PathToNESContent { get; set; }
[JsonProperty("pathToSNESContent")]
public string PathToSNESContent { get; set; }
[JsonProperty("pathToSEGAContent")]
public string PathToSEGAContent { get; set; }
[JsonProperty("lastSavedVolume")]
public double LastSavedVolume { get; set; }
}
public class Root
{
public Data Data { get; set; }
}
Deser (use Path.Combine to build paths, not string concat):
var x = JsonConvert.DeserializeObject<GV.Root>(File.ReadAllText(
Path.Combine(currentAssemblyPath, "Resources", "dataForLinks.json"))
));
Edit:
x.Data.PathToNESContent = "...";
and re-ser

Creating Inherited Response Objects

I am writing some integration with a third-party eLearning platform that returns a variety of responses in different schemas depending on the function of my restful API call. Since these responses come back in several different schemas, I'm trying to create a series of response object classes that inherit a base Response object class that would contain the common JSON sections (aka "data" and "message") and allow each individual response object to override or have additional members/classes based on the response being returned.
Here are a couple examples of how the schemas may differ.
Class Creation Return:
{
"data": [
{
"row_index": 0,
"success": true,
"message": "string"
}
]
}
User Creation Return:
{
"data": [
{
"message": [
{
"id": "string",
"message": "string"
}
],
"success": true,
"user_id": 0
}
]
}
As you can see, the different responses have different schemas. The Class Create only returns a message member within the data object, and the User Create has a separate message object altogether.
Since I can't have a class called data within each object because of ambiguity, I'm thinking I need to create a Base Response Object that contains the common members and allows me to override or add on the fly as necessary.
I've tried to create a Base Class:
public class BaseResponse
{
public List<Data> data;
public class Data
{
public bool success { set; get; }
}
}
as well as an example derived class:
public class ClassroomResponse : BaseResponse
{
public class Data
{
public int row_index { get; set; }
public string message { get; set; }
}
}
I'm not sure if this is only possible with functions and not classes as I'm trying to do above? Is there a way to add additional members to the derived object's (row_index and message are not members of all responses, so I'd like to be able to grab those as needed)
You could either create individual, distinct classes for each type, which might be the right option here depending on the other variants you haven't shown. Or you can use generics. There's a few ways you can do this, but here is one way you might do it.
A base class for the overall response:
public abstract class Response<TData>
{
[JsonProperty("data")]
public TData Data { get; set; }
}
A base class for the Data objects:
public abstract class BaseData<TMessage>
{
[JsonProperty("success")]
public bool Success { get; set; }
[JsonProperty("message")]
public TMessage Message { get; set; }
}
The response type for class creation:
public class ClassData : BaseData<string>
{
[JsonProperty("row_index")]
public int RowIndex { get; set; }
}
The response types for user creation:
public class UserData : BaseData<UserMessage>
{
[JsonProperty("user_id")]
public int UserId { get; set; }
}
public class UserMessage
{
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("message")]
public string Message { get; set; }
}
And finally the overall response types:
public class ClassResponse : Response<ClassData>
{ }
public class UserResponse : Response<UserData>
{ }
And now you can use the objects like you would normally:
var classData = new ClassResponse {Data = new ClassData {Message = ""}};
var classJson = JsonConvert.SerializeObject(classData);
var userData = new UserResponse {Data = new UserData {Message = new UserMessage {Message = ""}}};
var userJson = JsonConvert.SerializeObject(userData);
I will go by the generics route
Let's say that we have a response for Class creation as
public class ClassResponseObject {
public int row_index { get; set; }
public bool success { get; set; }
public string message { get; set; };
}
and for the User creation:
public class UserResponseObject {
public int user_id { get; set; }
public bool success { get; set; }
public MessageResponseObject message { get; set; };
}
and for the Message
public class MessageResponseObject {
public string id { get; set; }
public string message { get; set; };
}
after seeing the above code we are able to find that we have success property common in both the responses, so lets create a base class with that property and inherit these classes with that.
public class BaseResponseObject {
public bool success { get; set; }
}
public class ClassResponseObject : BaseResponseObject {
public int row_index { get; set; }
public string message { get; set; };
}
public class UserResponseObject : BaseResponseObject {
public int user_id { get; set; }
public MessageResponseObject message { get; set; };
}
at this point another common property we see is message, but both have different types. This can be solved with the use of generics. I am considering that there might be more types for the message property of the response, but it should work in either case.
for this let modify our BaseResponseObject and move the message property there
public class BaseResponseObject<TMessage> {
public bool success { get; set; }
public TMessage message { get; set; }
}
so our response objects will become something like this:
public class ClassResponseObject : BaseResponseObject<String> {
public int row_index { get; set; }
}
public class UserResponseObject : BaseResponseObject<MessageResponseObject> {
public int user_id { get; set; }
}
as the last step we need to define the final class for the actual response
public class APIResponse<TResponse> {
public List<TResponse> data { get; set; }
}
now when you are capture the response for the Class creation you can simply capture it in
APIResponse<ClassResponseObject>
similarly for the User creation, capture it in
APIResponse<UserResponseObject>
I hope this helps.

nested json array parsing

I am having a difficult time parsing a json response with C# asp.net. mostly with the array within array structure of this response. I have edited the post to reflect the json object. I think we can omit the deserialzation code.
{"Level1":
[
{
A:"some",
B:"more",
C:"stuff"
}
],"DataLevel":
[[
{ "AnotherLevel":
{
"File":"data"
},
"More":"stuff"
}
]]}
// C# code
public class JsonObject
{
public Level1[] level1 {get;set;}
public DataLevel[] datalevel {get;set;}
}
public class Level1
{
public string A {get;set;}
public string B {get;set;}
public string C {get;set;}
}
public class DataLevel
{
// ??
// Seems like this should be public AnotherLevel anotherlevel {get;set;}
public string More {get;set;}
}
Ok so looking at your data I would say your class definitions do not match the json you posted. Look closely at it. You have an object with 2 properties. One is an array of objects, the other is an array of object arrays. Below I have a different set of class definitions that should solve your problems.
public class OuterObject
{
public FirstArrayObject[];
public List<ObjInNestedArray[]>;
}
public class FirstArrayObject
{
public string A;
public string B;
public string C;
}
public class ObjInNestedArray
{
string property1;
AnotherLevel AnotherLevel;
}
public class AnotherLevelObj
{
string prop1;
}
OuterObject response = JsonConvert.DeserializeObject<OuterObject>(responseBodyAsString);
I don't know how good this is and didn't check if it is actually correct but you could try this website http://json2csharp.com/, but it might help you in some way!
This is the result I got when I used the json data you provided:
class Level1
{
public string A { get; set; }
public string B { get; set; }
public string C { get; set; }
}
public class RootObject
{
public List<Level1> Level1 { get; set; }
public List<List<>> DataLevel { get; set; }
}

Categories