ASP.NET API Call Exception: Cannot deserialize JSON Array. Requires JSON Object - c#

I want to call an POST API Call and get some data. i use the swagger to do the call.
The Problem is i got an Exception:
Cannot deserialize the current JSON array (e.g. [1,2,3]) into type because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.
To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List<T> that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.
This is on the razor page:
using var client = await httpClientHelper.GetHttpClientWithAccessToken();
var result = await client.PostJsonAsync<JobDetail>($"{_serviceClientOptions.Value.BetriebstoolServiceAddress}/api/AbaReport?scope={scope}&mandant={mandant}&reportname={reportname}", body);
Here you have the Controller
[HttpPost]
[Authorize(Roles = AppRoles.User)]
[ProducesResponseType(typeof(JobDetail), StatusCodes.Status200OK)]
[SwaggerOperation("StartReport")]
public async Task<JobDetail> StartReport(int scope, int mandant, string reportname, string body)
{
var result = await _abaReportService.StartReport(scope, mandant, reportname, body);
return result;
}
Now the Service
public async Task<JobDetail> StartReport(int scope, int mandant, string reportname, string body)
{
var getscope = await _abacusBetriebstoolDatastoreService.GetServerAccessByScopeIdAsync(scope);
var abacusClient = await _clientFactory.CreateClient<AbacusApiClient>(getscope.ServerDNS, getscope.UserID, getscope.Passwort);
var result = await abacusClient.GetReportAsync(mandant, reportname, body);
return result;
}
At a point in the generated Code from Swagger, it tries to deserialize to json
using (var responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))
using (var streamReader = new System.IO.StreamReader(responseStream))
using (var jsonTextReader = new Newtonsoft.Json.JsonTextReader(streamReader))
{
var serializer = Newtonsoft.Json.JsonSerializer.Create(JsonSerializerSettings);
var typedBody = serializer.Deserialize<T>(jsonTextReader); `<-- here ist the exception`
return new ObjectResponseResult<T>(typedBody, string.Empty);
}
Then i get the Exception!
And i see the point because when i try to call the api with Postman it looks like this:
The "result" is an array but it should be an object like in the example in swagger:
The response 'JobDetail' looks like this.
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.1.3.0 (Newtonsoft.Json v9.0.0.0)")]
public partial class JobDetail
{
/// <summary>The id of the user that last logged in or an empty string, if no-one logged in</summary>
[Newtonsoft.Json.JsonProperty("id", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public System.Guid? Id { get; set; }
[Newtonsoft.Json.JsonProperty("state", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
[Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
public JobDetailState? State { get; set; }
[Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public string Message { get; set; }
[Newtonsoft.Json.JsonProperty("finishedAt", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public System.DateTimeOffset? FinishedAt { get; set; }
[Newtonsoft.Json.JsonProperty("result", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public TypedMap Result { get; set; }
}
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.1.3.0 (Newtonsoft.Json v9.0.0.0)")]
public partial class TypedMap
{
[Newtonsoft.Json.JsonProperty("empty", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public bool? Empty { get; set; }
[Newtonsoft.Json.JsonProperty("size", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)]
public int? Size { get; set; }
}
Why is the response an array? It should be a JSON object like in the swagger example.
I hope you can help me. Thank you :)
I searched a lot and found some solutions like this or that. But in my Problem i think the problem is in the generated code. i don't know

The result property in the swagger is not correct. Swagger says is should be an object, while the response has it as an array. You should change the type of public TypedMap Result { get; set; } to a List. (but a list of which items?)

Related

Deserialize nested JSON with RestSharp Client

I'd like to consume a REST Api and deserialize the nested JSON Response. I created the classes using json2csharp.com.
JSON to consume
{
id: 32,
name: "test supply object",
formId: 4,
sortOrder: 0,
created: 1572902163907,
creator: "jsingler",
attributes: [
{
id: 144,
attribute: {
attributeName: "Description",
attributeType: "TextArea",
id: 8
},
attributeValue: "for development testing. do not delete or use."
},
{
id: 145,
attribute: {
attributeName: "Quantity",
attributeType: "NumberLong",
id: 10
},
attributeValue: "4"
}
]
}
JSON2CSHARP.COM output
public partial class Asset
{
[JsonProperty(PropertyName = "id")]
public int id { get; set; }
[JsonProperty(PropertyName = "name")]
public string name { get; set; }
[JsonProperty(PropertyName = "formId")]
public int formId { get; set; }
[JsonProperty(PropertyName = "sortOrder")]
public int sortOrder { get; set; }
[JsonProperty(PropertyName = "created")]
public long created { get; set; }
[JsonProperty(PropertyName = "creator")]
public string creator { get; set; }
public List<Attribute> attributes { get; set; }
}
public partial class Attribute
{
[JsonProperty(PropertyName = "ida")]
public int id { get; set; }
[JsonProperty(PropertyName = "attribute")]
public List<Attribute1> attribute { get; set; }
[JsonProperty(PropertyName = "attributeValue")]
public string attributeValue { get; set; }
}
public partial class Attribute1
{
[JsonProperty(PropertyName = "attributeName")]
public string attributeName { get; set; }
[JsonProperty(PropertyName = "attributeType")]
public string attributeType { get; set; }
[JsonProperty(PropertyName = "ida1")]
public int id { get; set; }
}
Method to consume API data
public static List<Asset> GetAllAssets()
{
var client = new RestClient("URL_USED");
var request = new RestRequest();
client.Authenticator = new HttpBasicAuthenticator("USERNAME", "PW");
var response = new RestResponse();
Task.Run(async () =>
{
response = await GetResponseContentAsync(client, request) as RestResponse;
}).Wait();
var AssetList = JsonConvert.DeserializeObject<List<Asset>>(response.Content);
return AssetList;
}
That always errors with:
An unhandled exception occurred while processing the request.
JsonSerializationException: Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[PVF_Web.Models.Attribute1]' 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<T>) 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 '[0].attributes[0].attribute.attributeName', line 1, position 158.
And then when I am able to get the JSON to deserialize, it doesn't return the attributes (the true purpose of the application).
Any suggests or thoughts would be appreciated.
EDIT 1
[HttpPut]
public void Send(Asset newJA, int Qty)
{
var client = new RestClient("URL_TO_USE" + newJA.id + ".json");
var request = new RestRequest("", Method.PUT);
request.AddObject(newJA);
client.Authenticator = new HttpBasicAuthenticator("USERNAME", "PW");
client.ExecuteAsync(request, response => {
Console.WriteLine(response.Content);
Debug.WriteLine(response.Content);
});
}
This always fails.
Your JSON is not valid. Go to https://jsonformatter.curiousconcept.com/ and check all the errors.
The property names must be between quotes and if you want it to be an array, you need to make it an array adding the square brackets - [ ] - to the beginning and end of you json.
First be sure your json is valid . You can have a look this side
The json properties must be inside quotes "" like this
"id"
.
Beside this your root object is not a list . So you have to change your deserializing code to:
var AssetList = JsonConvert.DeserializeObject<Asset>(response.Content);

C# Web Api - NUnit Testing - Newtonsoft.Json.JsonSerializationException

I need to deserialize the following JSON string.
{"status":"success","data":[{"id":4,"domainTitle":"Java","isDeleted":true},{"id":5,"domainTitle":"PHP","isDeleted":true},{"id":6,"domainTitle":"Angular","isDeleted":true}]}
The test code for the same is:
[Test]
public async Task TestGetDeletedDomainsAsync_UserDomains_StatusCodeOK()
{
using (var adminController = new AdminController(_adminService.Object))
{
//act
var response = _adminController.GetDeletedDomainsAsync();
var successStatus = await response.Content.ReadAsAsync<SuccessStatus>();
var returnData = JsonConvert.DeserializeObject<List<Domain>>(successStatus.Data.ToString());
// assert
Assert.Multiple(() =>
{
Assert.That(response, Is.TypeOf<HttpResponseMessage>());
Assert.That(returnData, Is.TypeOf<List<Domain>>());
Assert.AreEqual(response.StatusCode, HttpStatusCode.OK);
Assert.IsNotNull(successStatus);
Assert.AreEqual("success", successStatus.Status);
Assert.IsNotNull(returnData);
//checking if same object goes to service and also if that service is called once
_adminService.Verify(s => s.GetDeletedDomains(), Times.Once);
});
}
}
But when I try using the de-serializer, it gives an exception.
Newtonsoft.Json.JsonSerializationException : Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[IMS_NL.Models.Domain]' 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 line that displays the above error is --
var returnData = JsonConvert.DeserializeObject<List<Domain>>(successStatus.Data.ToString());
Help me with a solution. Thanks in advance.
You need to make a class which correspond your JSON string
public class Answer
{
public string Status { get; set; }
public List<Domain> Data { get; set; }
}
public class Domain
{
public int Id { get; set; }
public string DomainTitle { get; set; }
public bool IsDeleted { get; set; }
}
Then use
var returnData = JsonConvert.DeserializeObject<Answer>(successStatus.Data.ToString());
I think that your problem resides in the declaration of Domain class. You should define the below classes, according to the JSON you have posted:
public class Domain
{
public int id { get; set; }
public string domainTitle { get; set; }
public bool isDeleted { get; set; }
}
public class Result
{
public string status { get; set; }
public List<Domain> data { get; set; }
}
var returnData = JsonConvert.DeserializeObject<Result>(...);
You should replace the ... with the JSON you get from that you call.
Optionally, you could rename the above classes as you think that would be more suitable.

Convert json array into List of Objects

This is my Json List of Objects array that I stringified and sent to my controller
"[{\"Id\":\"fieldone\",\"Name\":\"fieldtwo\"}]"
How can I deserialize it in my controller and turn it into a list of Objects again?
Currently this is what I have:
var RoleList = JsonConvert.DeserializeObject<SampleViewModel>(Input.RoleList);
and these are my ViewModels
public class UserAddRoleListViewModel
{
public String Id { get; set; }
public String Name { get; set; }
}
public class SampleViewModel
{
public List<UserAddRoleListViewModel> Test { get; set; }
}
At the moment when I run it, I get this error
Newtonsoft.Json.JsonSerializationException: 'Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'App.Data.ViewModels.SampleViewModel' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.
What should I do to convert this into a list of UserAddRoleListViewModels?
EDIT: Added Controller and Relevant ViewModel
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult VerifyRole(SaveUserNewRoleViewModel Input)
{
var RoleList = JsonConvert.DeserializeObject<SampleViewModel>(Input.RoleList);
return null;
}
public class SaveUserNewRoleViewModel
{
[Required]
public String RoleId { get; set; }
public String RoleName { get; set; }
public String RoleList { get; set; }
}
Based on the shown JSON array and the error message indicating that you are trying to convert an array to a single object, it looks like you were suppose to do
var RoleList = JsonConvert.DeserializeObject<List<UserAddRoleListViewModel>>(Input.RoleList);
in order to parser the JSON correctly into a List<>
To make the following working
var RoleList = JsonConvert.DeserializeObject<SampleViewModel>(Input.RoleList);
your json should be like below
"{ Test:[{\"Id\":\"fieldone\",\"Name\":\"fieldtwo\"}] }"
Otherwise, for correct result fro your json
"[{\"Id\":\"fieldone\",\"Name\":\"fieldtwo\"}]"
use below
var RoleList = JsonConvert.DeserializeObject<List<UserAddRoleListViewModel>>(Input.RoleList);

JSON in C#: How do I get all objects in a json string below a certain class?

I am trying to get everything below apps and put the values inside a Dictionary<string, Games>
I am using the below code.
Class:
public class Games
{
public int AppId { get; set; }
public string Name { get; set; }
}
Code:
public Dictionary<string, Games> GetAllGames()
{
//http://api.steampowered.com/ISteamApps/GetAppList/v0002/?key=STEAMKEY&format=json
var url = "http://api.steampowered.com/ISteamApps/GetAppList/v0002/?key=STEAMKEY&format=json";
HttpWebRequest WebReq = (HttpWebRequest)WebRequest.Create(string.Format(url));
WebReq.Method = "GET";
HttpWebResponse WebResp = (HttpWebResponse)WebReq.GetResponse();
Console.WriteLine(WebResp.StatusCode);
Console.WriteLine(WebResp.Server);
string jsonString;
using (Stream stream = WebResp.GetResponseStream())
{
StreamReader reader = new StreamReader(stream, System.Text.Encoding.UTF8);
jsonString = reader.ReadToEnd();
}
var t = JObject.Parse(jsonString).SelectToken("applist").ToString();
var s = JObject.Parse(t).SelectToken("apps").ToString();
Dictionary<string, Games> gamesList = JsonConvert.DeserializeObject<Dictionary<string, Games>>(s);
return gamesList;
}
Error:
Newtonsoft.Json.JsonSerializationException
HResult=0x80131500
Message=Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'System.Collections.Generic.Dictionary`2[System.String,LudumPricer.Games]' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.
To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List<T> that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.
Path '', line 1, position 1.
JSON sample:
{
"applist":{
"apps":[
{
"appid":5,
"name":"Dedicated Server"
},
{
"appid":7,
"name":"Steam Client"
},
{
"appid":8,
"name":"winui2"
},
{
"appid":10,
"name":"Counter-Strike"
}
]
}
}
I want to get everything under the apps attribute and put them in a Dictionary <string, Games>
I am using the newtonsoft json.net library
Just convert and use ToDictionary
Given
public class App
{
public int appid { get; set; }
public string name { get; set; }
}
public class Applist
{
public List<App> apps { get; set; }
}
public class RootObject
{
public Applist applist { get; set; }
}
Usage
var root = JsonConvert.DeserializeObject<RootObject>(jsonString);
var dict = root.applist.apps.ToDictionary(x => x.appid, x => x.name);
Enumerable.ToDictionary Method (IEnumerable, Func)
Creates a Dictionary from an IEnumerable according to
a specified key selector function.

deserialize json array list in c#

I'm working on a project which has as backend mainly C#, but I'm not an experienced C# dev so I'm not able to figure out hot to fix a json deserialization of an list of objects. The following function is what takes care of the deserialization, but I get an error :
using System.IO;
using System.Web;
using Raven.Imports.Newtonsoft.Json;
namespace Corina.Web.Handlers
{
public class JsonRequestHandler
{
public T Handle<T>(HttpContextBase context)
{
string requestData;
context.Request.InputStream.Position = 0;
using (var inputStream = new StreamReader(context.Request.InputStream))
{
requestData = inputStream.ReadToEnd();
}
return JsonConvert.DeserializeObject<T>(requestData, new Raven.Imports.Newtonsoft.Json.Converters.StringEnumConverter());
}
}
}
Error :
Cannot deserialize the current JSON array (e.g. [1,2,3]) into type
'Corina.Web.Views.DocumentViewModel' because the type requires a JSON
object (e.g. {"name":"value"}) to deserialize correctly.
To fix this error either change the JSON to a JSON object (e.g.
{"name":"value"}) or change the deserialized type to an array or a
type that implements a collection interface (e.g. ICollection, IList)
like List that can be deserialized from a JSON array.
JsonArrayAttribute can also be added to the type to force it to
deserialize from a JSON array.
Can anyone tell me how do I make the deserialization on a list of objects instead of an object ?
You have to create this class and create a method like below :
public class Demo
{
public string Name;
public string Type;
public string Value;
public string ChildContentType;
public string ChildMetadata;
}
public void Deserialize()
{
string jsonObjString = "[{\"Name\": \"Description\",\"Type\": \"Text\",\"Value\": \"XXX\",\"ChildContentType\": \"Value\",\"C??hildMetadata\": \"YYY\"}]";
var ser = new JavaScriptSerializer();
var arreyDemoObj = ser.Deserialize<Demo[]>(jsonObjString);
foreach (Demo objDemo in arreyDemoObj)
{
//Do what you want with objDemo
}
}
Note that you need to add reference for JavaScriptSerializer.
Don't know the structure of your json data but i guess you are using some custom classes to deserialize with DataContractJsonSerializer you can deserialize in the following manner
Json list:
var testdata = "[{\"name\":\"numToRetrieve\",\"value\":\"3\",\"label\":\"Number of items to retrieve:\"},{\"name\":\"showFoo\",\"value\":\"on\",\"label\":\"Show foo?\"}, {\"name\":\"title\",\"value\":\"Foo\",\"label\":\"Foo:\"}]";
DataContractJsonSerializer js =
new DataContractJsonSerializer(typeof (List<FooDef>));
var stream = new MemoryStream(Encoding.UTF8.GetBytes(testdata));
var foo = js.ReadObject(stream);
stream.Close();
[DataContract]
public sealed class FooDef
{
[DataMember(Name = "name", IsRequired = true)]
public string Name { get; set; }
[DataMember(Name = "value", IsRequired = true)]
public string Value { get; set; }
[DataMember(Name = "label", IsRequired = true)]
public string Label { get; set; }
}

Categories

Resources