why wont my code deserialize into my model? [duplicate] - c#

This question already has answers here:
Cannot deserialize the JSON array (e.g. [1,2,3]) into type ' ' because type requires JSON object (e.g. {"name":"value"}) to deserialize correctly
(6 answers)
Closed 3 years ago.
I'm making a call to an external api service, however i am getting an exception and it wont deserilize into my model:
my response is
[
{
"$type": "Tfl.Api.Presentation.Entities.RoadCorridor, Tfl.Api.Presentation.Entities",
"id": "a2",
"displayName": "A2",
"statusSeverity": "Good",
"statusSeverityDescription": "No Exceptional Delays",
"bounds": "[[-0.0857,51.44091],[0.17118,51.49438]]",
"envelope": "[[-0.0857,51.44091],[-0.0857,51.49438],[0.17118,51.49438],[0.17118,51.44091],[-0.0857,51.44091]]",
"url": "/Road/a2"
}
]
and my code is
public class TravelService : ITravelService
{
string baseURL = "https://foo.bar/blah.blah";
private readonly IMapToNew<Road, RoadDto> _mapper;
public TravelService()
{
}
public TravelService(IMapToNew<Road, RoadDto> mapper)
{
_mapper = mapper;
}
public async Task<RoadDto> GetTravelInformation()
{
var road = GetRoad();
Console.WriteLine(road.Result.DisplayName);
return new RoadDto
{
DisplayName = road.Result.DisplayName,
StatusSeverityDescription = road.Result.DisplayName,
StatusSeverity = road.Result.DisplayName
};
}
private async Task <Road> GetRoad()
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(baseURL);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage Res = await client.GetAsync(baseURL);
if (Res.IsSuccessStatusCode)
{
var roadResponse = Res.Content.ReadAsStringAsync().Result;
Road road = JsonConvert.DeserializeObject<Road>(roadResponse);
return new Road
{
DisplayName = road.DisplayName,
StatusSeverity = road.StatusSeverity,
StatusSeverityDescription = road.StatusSeverityDescription
};
}
return new Road { };
}
}
my road class is:
public class Road
{
[JsonProperty(PropertyName = "$type")]
public string PropertyName { get; set; }
public string Id { get; set; }
public string DisplayName { get; set; }
public string StatusSeverity { get; set; }
public string StatusSeverityDescription { get; set; }
public string Bounds { get; set; }
public string Envelope { get; set; }
public string Url { get; set; }
}
when i run my code i'm getting an exception: 'One or more errors occurred. (One or more errors occurred. (Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'Travel.Responses.Road' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly

As the exception message explains, you're trying to deserialize into a Road, but the payload is actually a JSON array that contains a Road inside of it. You could do something like this:
var roads = JsonConvert.DeserializeObject<Road[]>(roadResponse);
var road = roads.Single(); // assuming you know the array only has one entry

List<Road> road = JsonConvert.DeserializeObject<List<Road>>(roadResponse);
this worked for me!
thanks all

Related

How to fix error: JsonSerializationException: Cannot deserialize the current JSON object

This is what the body looks like:
{
"_total": 3,
"users": [
{
"username": "person1",
"points": 3
},
{
"username": "person2",
"points": 2
},
{
"username": "person3",
"points": 1
}
]
}
The code:
public class UserData
{
public string username { get; set; }
public int points { get; set; }
}
using (var response = await client.SendAsync(request))
{
response.EnsureSuccessStatusCode();
var body = await response.Content.ReadAsStringAsync();
var data = JsonConvert.DeserializeObject<List<UserData>>(body);
foreach (UserData userdata in data)
{
Debug.Log(userdata.username + ": " + userdata.points);
}
}
The Error:
JsonSerializationException: Cannot deserialize the current JSON object
(e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[UserData]'
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.
The class does not match the JSON structure, hence you are getting JsonSerializationException Exception.
Your model should look something like that:
public class RootClass
{
public int _total { get; set; }
public List<User> users { get; set; }
}
public class User
{
public string username { get; set; }
public int points { get; set; }
}
Than you can do this:
using (var response = await client.SendAsync(request))
{
response.EnsureSuccessStatusCode();
var body = await response.Content.ReadAsStringAsync();
var data = JsonConvert.DeserializeObject<RootClass>(body);
foreach (User userdata in data.users)
{
Debug.Log(userdata.username + ": " + userdata.points);
}
}
you can parse a json string at first and after this to deserialize it to a list of UserData
var data = JObject.Parse(body)["users"].ToObject<List<UserData>>();

How to pass class name to JSON DeserializeObject at runtime?

Given that I have JSON like this:
[
{
"ct_IncludeinSummary": true,
"ct_allocationid": "12345",
"allocationclassname": "group1",
"allocationname": "name1",
"opendate": "2018-12-30T05:00:00",
"closeddate": null,
"yearendvalue": 2863.93,
"qrgendvalue": 2.06,
"ct_risk": 2
},
{
"ct_IncludeinSummary": true,
"ct_allocationassetid": "5678",
"allocationclassname": "group2",
"allocationname": "name2",
"opendate": "2018-12-30T05:00:00",
"closeddate": null,
"yearendvalue": 13538223.76,
"qrgendvalue": 17337143.84,
"ct_risk": 3
},
{
"ct_IncludeinSummary": true,
"ct_allocationassetid": "89012",
"allocationclassname": "group3",
"allocationname": "name3",
"opendate": "2019-11-18T05:00:00",
"closeddate": null,
"yearendvalue": 0.0,
"qrgendvalue": 561480.62,
"ct_risk": 5
}
]
I can deserialize the results into a defined model and it works just fine.
var summaryConciseData = JsonConvert.DeserializeObject<List<SummaryConciseData>>(jsonresult);
public class Summaryconcisedata
{
public Summaryconcisedata(
bool ct_IncludeinSummary,
string ct_allocationassetid,
string allocationclassname,
string allocationname,
DateTime opendate,
DateTime? closeddate,
double? yearendvalue,
double? qrgendvalue,
int ct_risk
)
{
this.IncludeinSummary = ct_IncludeinSummary;
this.allocationid = ct_allocationassetid;
this.allocationclassname = allocationclassname;
this.allocationname = allocationname;
this.opendate = opendate;
this.closeddate = closeddate;
this.yearendvalue = yearendvalue;
this.qrgendvalue = qrgendvalue;
this.risk = risk;
}
public bool IncludeinSummary { get; }
public string allocationid { get; }
public string allocationclassname { get; }
public string allocationname { get; }
public DateTime opendate { get; }
public DateTime? closeddate { get; }
public double? yearendvalue { get; }
public double? qrgendvalue { get; }
public int risk { get; }
}
What I am trying to do is to have a large number of classes (Around 30 in all) I can deserialize and load into models
var summaryConciseData = JsonConvert.DeserializeObject(jsonresult, Type.GetType("API.HelperClass.SummaryConciseData"));
I get the following error:
Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'API.HelperClass.SummaryConciseData' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.
Any idea on how I this can be a List<> ?
I've gone through most all of the similar questions to be found but none refer to any data that is in a List
MakeGenericType on list/ienumerable type should work just fine:
var listType = typeof(List<>).MakeGenericType(Type.GetType("API.HelperClass.SummaryConciseData");
var summaryConciseData = JsonConvert.DeserializeObject(jsonresult, listType);

How to extract those values from the JSON string

I have this JSON string but are not sure how I will parse out the values that are inside:
has
has2
I do succeed to parse out the "id" correctly but are not sure how to access:
CORS
CORS2
CORS3
CORS4
I get the error:
'Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.String[]' because the type requires a JSON array (e.g. [1,2,3])
I have pasted the JSON in the pastebin:
https://pastebin.com/iWgGV9VK
The code I have:
public void getInfo()
{
String JSONstring = "{ id: 'hello', name: 'Hello',has:{ CORS: false,CORS2: true},has2:{ CORS3: false,CORS4: true}}";
String id = ""; List<String> has = new List<String>(); List<String> has2 = new List<String>();
var deserializedTicker = JsonConvert.DeserializeObject<JsonInfo>(JSONstring);
id = deserializedTicker.id;
has = deserializedTicker.has.ToList();
has2 = deserializedTicker.has.ToList();
}
public class JsonInfo
{
public String id { get; set; }
public String[] has { get; set; }
public String[] has2 { get; set; }
}
I am trying with the dynamic approach using an object but gets an error here also:
''Newtonsoft.Json.Linq.JValue' does not contain a definition for 'id''
//responseBody holds the JSON string
dynamic stuff = JsonConvert.DeserializeObject(responseBody);
foreach (var info in stuff)
{
dynamic id = info.Value.id; //''Newtonsoft.Json.Linq.JValue' does not contain a definition for 'id''
dynamic has = info.Value.has;
dynamic has2 = info.Value.has2;
if (has != null && has2 != null)
{
dynamic cors = has.CORS;
if(cors != null)
{
MessageBox.Show(cors.ToString());
}
}
}
First off, let's correct your JSON:
{
"id": "hello",
"name": "Hello",
"has": {
"CORS": false,
"CORS2": true
},
"has2": {
"CORS3": false,
"CORS4": true
}
}
Now, the problem you are experiencing is because you are attempting to deserialize the value in "has" and "has2" as arrays. In the JSON, they are not arrays; they are objects. As such, you need to define new classes with the same properties so the JSON can be properly deserialized:
public class JsonInfo
{
public string id { get; set; }
public string name { get; set; }
public JsonHasInfo has { get; set; }
public JsonHas2Info has2 { get; set; }
}
public class JsonHasInfo
{
public bool CORS { get; set; }
public bool CORS2 { get; set; }
}
public class JsonHas2Info
{
public bool CORS3 { get; set; }
public bool CORS4 { get; set; }
}
Now you should be able to deserialize the (correct) JSON properly:
String JSONstring = "{ \"id\": \"hello\", \"name\": \"Hello\", \"has\": { \"CORS\": false, \"CORS2\": true }, \"has2\": { \"CORS3\": false, \"CORS4\": true } }\";"
var deserializedTicker = JsonConvert.DeserializeObject<JsonInfo>(JSONstring);
You json was incorrect, the key has contains a dict no list.
You need change your deserialize to dictionary or change your json.
Here you can see an example:
https://json-schema.org/understanding-json-schema/reference/array.html#array
In your JSON, has is an object, not an array. You should model your class to support an object containing the attributes CORS, CORS2, and so on, and so forth.
Edit: If you want to stick to has being an array, you should change your JSON to match what an array expects, which could be like: has: [ false, true ], and omit the CORS thing.

RestSharp client returns all properties as null when deserializing JSON response

I'm trying to do a very simple example of using RestSharp's Execute method of querying a rest endpoint and serializing to a POCO. However, everything I try results in a response.Data object that has all properties with a NULL value.
Here is the JSON response:
{
"Result":
{
"Location":
{
"BusinessUnit": "BTA",
"BusinessUnitName": "CASINO",
"LocationId": "4070",
"LocationCode": "ZBTA",
"LocationName": "Name of Casino"
}
}
}
Here is my test code
[TestMethod]
public void TestLocationsGetById()
{
//given
var request = new RestRequest();
request.Resource = serviceEndpoint + "/{singleItemTestId}";
request.Method = Method.GET;
request.AddHeader("accept", Configuration.JSONContentType);
request.RootElement = "Location";
request.AddParameter("singleItemTestId", singleItemTestId, ParameterType.UrlSegment);
request.RequestFormat = DataFormat.Json;
//when
Location location = api.Execute<Location>(request);
//then
Assert.IsNotNull(location.LocationId); //fails - all properties are returned null
}
And here is my API code
public T Execute<T>(RestRequest request) where T : new()
{
var client = new RestClient();
client.BaseUrl = Configuration.ESBRestBaseURL;
//request.OnBeforeDeserialization = resp => { resp.ContentLength = 761; };
var response = client.Execute<T>(request);
return response.Data;
}
And finally, here is my POCO
public class Location
{
public string BusinessUnit { get; set; }
public string BusinessUnitName { get; set; }
public string LocationId { get; set; }
public string LocationCode { get; set; }
public string LocationName { get; set; }
}
Additionally, the ErrorException and ErrorResponse properties on the response are NULL.
This seems like a very simple case, but I've been running around in circles all day! Thanks.
What is the Content-Type in the response? If not a standard content type like "application/json", etc. then RestSharp won't understand which deserializer to use. If it is in fact a content type not "understood" by RestSharp (you can verify by inspecting the Accept sent in the request), then you can solve this by doing:
client.AddHandler("my_custom_type", new JsonDeserializer());
EDIT:
Ok, sorry, looking at the JSON again, you need something like:
public class LocationResponse
public LocationResult Result { get; set; }
}
public class LocationResult {
public Location Location { get; set; }
}
And then do:
client.Execute<LocationResponse>(request);

Deserializing array of enum values wih JSON.NET

I'm trying to use JSON.NET to deserialize a response from a third-party web service. This is the full code of my (contrived) example showing what I'm trying to do:
namespace JsonNetTests
{
public enum Parameter
{
Alpha = 1,
Bravo = 2,
Charlie = 3,
Delta = 4
}
public class ResponseElement
{
public int Id { get; set; }
public string Name { get; set; }
[JsonProperty(ItemConverterType = typeof(StringEnumConverter))]
public Parameter[] Parameters { get; set; }
}
public class ResponseBody
{
public string Locale { get; set; }
public string[] Errors { get; set; }
public ResponseElement[] ResponseElements { get; set; }
}
[TestFixture]
public class JsonNetTest
{
[Test]
public void TestEnumArray()
{
string jsonResponse = #"
{""ResponseBody"": {
""Locale"": ""en-US"",
""Errors"": [],
""ResponseElements"": [{
""Id"": 1,
""Name"": ""ABC"",
""Parameters"" : {
""Parameter"" : ""Alpha""
},
}, {
""Id"": 2,
""Name"": ""BCD"",
""Parameters"" : {
""Parameter"" : ""Bravo""
},
}
]
}}
";
JObject rootObject = JObject.Parse(jsonResponse);
JToken rootToken = rootObject.SelectToken("ResponseBody");
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.MissingMemberHandling = MissingMemberHandling.Error;
ResponseBody body = JsonConvert.DeserializeObject<ResponseBody>(rootToken.ToString(), settings);
foreach (var element in body.ResponseElements)
{
Console.WriteLine(string.Format("{0}: {1}", element.Id, element.Name));
foreach (var parameter in element.Parameters)
{
Console.WriteLine(string.Format("\t{0}", parameter));
}
}
}
}
}
I get the following exception:
Newtonsoft.Json.JsonSerializationException : Cannot deserialize JSON object (i.e. {"name":"value"}) into type 'JsonNetTests.Parameter[]'.
The deserialized type should be a normal .NET type (i.e. not a primitive type like integer, not a collection type like an array or List) or a dictionary type (i.e. Dictionary).
To force JSON objects to deserialize add the JsonObjectAttribute to the type. Path 'ResponseElements[0].Parameters.Parameter', line 9, position 21.
I tried to use the ItemConverterType attribute to specify how the array should be deserialised:
[JsonProperty(ItemConverterType = typeof(StringEnumConverter))]
But this does not help either. Can someone advise?
You're trying to stuff an object into an array. ResponseElement.Parameters is an array of enums where you're json code is using an object to describe each parameter.
Your json looks like this:
// some json
"Parameters" : {
"Parameter" : "Alpha"
},
// more json
But to translate it into an array of enums it should look like this:
// some json
"Parameters" : [ "Alpha", "Bravo" ],
// more json
If you can't change the json, you can change your model as so:
public enum ParameterEnum
{
Alpha = 1,
Bravo = 2
}
public ParameterContainer
{
[JsonProperty(ItemConverterType = typeof(StringEnumConverter))]
public ParameterEnum Parameter {get;set;}
}
public class ResponseElement
{
public int Id { get; set; }
public string Name { get; set; }
public ParameterContainer[] Parameters { get; set; }
}
Effectively, you'll serialize the json into an array of ParameterContainers which will expose their values.

Categories

Resources