I have a json object that I need to deserialize, I'm using Json.NET to make these operations.
when it's a simple object, its quite easy to do it, but I cant figure out how to deserialize this string
json
{
"aspsp-list":
[
{
"id":"424250495054504C",
"bic":"BBPIPTPL",
"bank-code":"0010",
"aspsp-cde":"BBPI",
"name":"BANCO BPI, SA",
"logoLocation":"../img/corporate/theBank.jpg",
"api-list":[{
"consents":["BBPI/v1/consents"],
"payments":["BBPI/v1/payments"],
"accounts":["BBPI/v1/accounts"],
"funds-confirmations":["BBPI/v1/funds-confirmations"]
}]
},
{
"id":"544F54415054504C",
"bic":"TOTAPTPL",
"bank-code":"0018",
"aspsp-cde":"BST",
"name":"BANCO SANTANDER TOTTA, SA",
"logoLocation":"../img/openBank.svc",
"api-list":[{
"consents":["BBPI/v1/consents"],
"payments":["BBPI/v1/payments"],
"accounts":["BBPI/v1/accounts"],
"funds-confirmations":["BST/v1/funds-confirmations"]
}]
}
]
}
Now the code I have so far:
internal class AspspListResponseResource
{
// Report with the list of supported ASPSPs. Each ASPSP will include the list of available API endpoints and the logo.
[JsonProperty(PropertyName = "aspsp-list")]
public AspspList[] AspspList { get; set; }
public AspspListResponseResource() { /* Empty constructor to create the object */ }
public AspspListResponseResource(string jsonString)
{
//var alrr = JsonConvert.DeserializeObject<AspspListResponseResource>(jsonString);
JObject jObject = JObject.Parse(jsonString);
JToken jUser = jObject["aspsp-list"];
// The root object here is coming with certain fields as null, such as 'aspsp-cde', 'bank-code' and 'api-list'
AspspListResponseResource root = JsonConvert.DeserializeObject<AspspListResponseResource>(jsonString);
}
}
internal class Aspsp
{
// ASPSP Id
[JsonProperty(PropertyName = "id")]
public string Id { get; set; } = "";
// Bank Identifier Code
[JsonProperty(PropertyName = "bic")]
public string Bic { get; set; } = "";
// IBAN Bank Identifier
[JsonProperty(PropertyName = "bank-code")]
public string BankCode { get; set; } = "";
// ASPSP Code to use in the endpoint
[JsonProperty(PropertyName = "aspsp-cde")]
public string AspspCde { get; set; } = "";
// Institution name
[JsonProperty(PropertyName = "name")]
public string Name { get; set; } = "";
// Bank logo location
[JsonProperty(PropertyName = "logoLocation")]
public string LogoLocation { get; set; } = "";
// Bank Supported API List
[JsonProperty(PropertyName = "api-list")]
public ApiLink[] ApiList { get; set; }
}
internal class ApiLink
{
// Consents Link List
[JsonProperty(PropertyName = "consents")]
public string[] Consents { get; set; } = { "" };
// Payments Link List
[JsonProperty(PropertyName = "payments")]
public string[] Payments { get; set; } = { "" };
// Accounts Link List
[JsonProperty(PropertyName = "accounts")]
public string[] Accounts { get; set; } = { "" };
// Balances Link List
[JsonProperty(PropertyName = "balances")]
public string[] Balances { get; set; } = { "" };
// Transaction Link List
[JsonProperty(PropertyName = "transaction")]
public string[] Transaction { get; set; } = { "" };
// Funds-Confirmations Link List
[JsonProperty(PropertyName = "funds-confirmations")]
public string[] FundsConfirmations { get; set; } = { "" };
}
Sum of the values of the deserialized object are null, even though the jsonString definitelly has data.
How should I proceed here?
The way your json is structured:
{
"aspsp-list":
[
{
"id":"123123123",
"bic":"BBPIPTPL",
"bank-code":"0010",
"aspsp-cde":"BBPI",
"name":"BANCO BPI, SA",
"logoLocation":"../img/corporate/theBank.jpg",
"api-list":[{
"consents":"",
"payments":"",
"accounts":"",
"funds-confirmations":""
}]
},
{
"id":"1434231231",
"bic":"TOTAPTPL",
"bank-code":"0018",
"aspsp-cde":"BST",
"name":"BANCO SANTANDER TOTTA, SA",
"logoLocation":"../img/openBank.svc",
"api-list":[{
"consents":"",
"payments":"",
"accounts":"",
"funds-confirmations":""
}]
}
]
}
This is telling us that you have an object, with an array of objects called Aspsp-list.
If this is what you intended great.
We need to create an object similar to this
public class RootJsonObject {
public IEnumerable<Aspsp> Aspsp-list {get; set;}
}
To deserialize to this simply:
JsonConvert.Deserialize<RootJsonObject>(/*your json string*/ value);
If you wanted to only work with the array, you would need to deserialize purely to an IEnumerable/Array But you would also need to change your json to just be an array, not an object wrapping an array.
I managed to make it work now, my problem wasn't exactly that I couldn't deserialize because of data types or structure (at least not completely, comment that said that the structure was wrong was partly right).
So, this is how I solved the problem:
-> Created an empty costructor on the AspspListResponseResource class, so that the method JsonConvert.DeserializeObject<T>(jsonString) could create an instance of the object, I thought of this since the only constructor took a string, and so there was no other contructor for JsonConvert to use.
-> Put the field names of with help of [JsonProperty(PropertyName = "")], but this still gave me the deserialized object as null, or with some null fields.
-> commented the fields Transaction and FundsConfirmations of the ApiLink class, these fields were in the documentation of the Web API so I put them in, but looking at the json string I recieve, it look like they aren't being used, so I just commented them
and after these changes the code now works flawlessly:
The code:
internal class AspspListResponseResource
{
// Report with the list of supported ASPSPs. Each ASPSP will include the list of available API endpoints and the logo.
[JsonProperty(PropertyName = "aspsp-list")]
public Aspsp[] AspspList { get; set; }
public AspspListResponseResource() { /* Empty constructor to create the object */ }
public AspspListResponseResource(string jsonString)
{
AspspListResponseResource root = JsonConvert.DeserializeObject<AspspListResponseResource>(jsonString);
this.AspspList = root.AspspList;
}
}
internal class Aspsp
{
// ASPSP Id
[JsonProperty(PropertyName = "id")]
public string Id { get; set; } = "";
// Bank Identifier Code
[JsonProperty(PropertyName = "bic")]
public string Bic { get; set; } = "";
// IBAN Bank Identifier
[JsonProperty(PropertyName = "bank-code")]
public string BankCode { get; set; } = "";
// ASPSP Code to use in the endpoint
[JsonProperty(PropertyName = "aspsp-cde")]
public string AspspCde { get; set; } = "";
// Institution name
[JsonProperty(PropertyName = "name")]
public string Name { get; set; } = "";
// Bank logo location
[JsonProperty(PropertyName = "logoLocation")]
public string LogoLocation { get; set; } = "";
// Bank Supported API List
[JsonProperty(PropertyName = "api-list")]
public ApiLink[] ApiList { get; set; }
}
internal class ApiLink
{
// Consents Link List
[JsonProperty(PropertyName = "consents")]
public string[] Consents { get; set; } = { "" };
// Payments Link List
[JsonProperty(PropertyName = "payments")]
public string[] Payments { get; set; } = { "" };
// Accounts Link List
[JsonProperty(PropertyName = "accounts")]
public string[] Accounts { get; set; } = { "" };
// Balances Link List
[JsonProperty(PropertyName = "balances")]
public string[] Balances { get; set; } = { "" };
//// Transaction Link List
//[JsonProperty(PropertyName = "transaction")]
//public string[] Transaction { get; set; } = { "" };
//
//// Funds-Confirmations Link List
//[JsonProperty(PropertyName = "funds-confirmations")]
//public string[] FundsConfirmations { get; set; } = { "" };
}
You need to create a contructor for the ApiLink class so you can do the following:
var apiListRaw = new ApiLink(value["api-list"][0] as JObject);
The constructor would look something like the following:
public ApiLink(JObject json)
{
Consensts = (string[])json["consents"];
...
}
Related
I have this JSON object returned from API:
[
{
"batchId": 789,
"debtId": 1841,
"dateAdded": "2021-07-27T16:01:39.41",
"debtCategoryId": 2,
"agreementNumber": 78262155,
"clientNumber": 1068055,
"clientName": "Client Two"
},
{
"batchId": 866,
"debtId": 1918,
"dateAdded": "2021-08-25T14:47:18.13",
"debtCategoryId": 2,
"agreementNumber": 1000140792,
"clientNumber": 11213287,
"clientName": "Client One"
}
]
I'm trying to convert that to a C# object which has this structure:
public class DebtConfirmationResponse
{
public List<DebtConfirmation> DebtConfirmations { get; set; }
}
Where DebtConfirmation has these properties:
public class DebtConfirmation
{
public int BatchId { get; set; }
public int DebtId { get; set; }
public string DateAdded { get; set; }
public int DebtCategoryId { get; set; }
public string AgreementNumber { get; set; } = string.Empty;
public string ClientNumber { get; set; } = string.Empty;
public string ClientName { get; set; } = string.Empty;
}
The error I'm getting is:
the json value could not be converted to the name of the model path $
linenumber 0 bytepositioninline 1
Is there anything wrong with the way how the model is being setup?
I also tried converting to the same model with batch id only as a property and I got the same message.
You define AgreementNumber, ClientNumber as strings in your C# code, but this properties is numbers in json, so you have to define it as longs.
And the another point is that you don't need a wrapper around DebtConfirmation class. Deserealize your json into ICollection, IList or just List of DebtConfirmation objects.
I used the quicktype.io for retrieving C# classes from json example you provide. This is very helpful for those who doesn't want to manually generate the models for their JSON strings.
Here is the code sample.
The output is:
789
866
using System.Text.Json;
using System.Text.Json.Serialization;
string json = "[\n {\n \"batchId\": 789,\n \"debtId\": 1841,\n \"dateAdded\": \"2021-07-27T16:01:39.41\",\n \"debtCategoryId\": 2,\n \"agreementNumber\": 78262155,\n \"clientNumber\": 1068055,\n \"clientName\": \"Client Two\"\n },\n {\n \"batchId\": 866,\n \"debtId\": 1918,\n \"dateAdded\": \"2021-08-25T14:47:18.13\",\n \"debtCategoryId\": 2,\n \"agreementNumber\": 1000140792,\n \"clientNumber\": 11213287,\n \"clientName\": \"Client One\"\n }\n]";
var data = JsonSerializer.Deserialize<ICollection<DebtConfirmation>>(json);
foreach (DebtConfirmation current in data)
{
Console.WriteLine(current.BatchId);
}
public partial class DebtConfirmation
{
[JsonPropertyName("batchId")]
public long BatchId { get; set; }
[JsonPropertyName("debtId")]
public long DebtId { get; set; }
[JsonPropertyName("dateAdded")]
public DateTimeOffset DateAdded { get; set; }
[JsonPropertyName("debtCategoryId")]
public long DebtCategoryId { get; set; }
[JsonPropertyName("agreementNumber")]
public long AgreementNumber { get; set; }
[JsonPropertyName("clientNumber")]
public long ClientNumber { get; set; }
[JsonPropertyName("clientName")]
public string ClientName { get; set; }
}
You can use #GeorgyTarasov's answer. But it is definitely not the simplest option.
You can simply use JsonNamingPolicy.CamelCase.
Then you would simply do...
var options = new JsonSerializerOptions
{
DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
};
var ret = JsonSerializer.Deserialize<DebtConfirmation>(payload, options);
If you are using AspNet Core, you can register the option here
services.AddControllers()
.AddJsonOptions(options =>
{
options.JsonSerializerOptions.DictionaryKeyPolicy = JsonNamingPolicy.CamelCase;
});
I am retrieving the following JSON via a POST to an API
{
"State":"Andhra_Pradesh",
"District":"Guntur",
"Fact":"SELECT",
"Description":"",
"FactDate":"",
"FactNumber":"",
"FactType":"SELECT",
"Fact":{"Id":"1"}
}
I am able to execute the Ajax request via javascript, but I also want to consume the API through C# code.
I am using the below code, but I'm not quite sure on how to add the Fact object?
var values = new Dictionary<string, string>
{
{ "State", selectedState },
{ "District", selectedDistrict },
{ "Fact", ""},
{ "FactType", ""},
{ "FactNumber", ""},
{ "Description", ""},
{"Fact", "{Id,1}" },
{"FactDate", factDate.Date.ToString() }
};
using (var httpClient = new HttpClient())
{
var content = new FormUrlEncodedContent(values);
var response = await httpClient.PostAsync("http://api.in/" + "test", content);
}
How do I add the Fact object to Dictionary?
You'll probably need to define the data you are sending as actual class before using httpclient.
If you had only name value pairs then you could have used the NameValueCollection and sent as a formurlencoded but since you have a complex type, you might consider this below.
See below.
public class Rootobject
{
public string State { get; set; }
public string District { get; set; }
public Fact Fact { get; set; }
public string Description { get; set; }
public string CaseDate { get; set; }
public string FactNumber { get; set; }
public string FactType { get; set; }
}
public class Fact
{
public string Id { get; set; }
}
Usage is as below. be sure to include a reference to System.Net.Http.Formatting.dll
var client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var model = new Rootobject { State = "Andhra_Pradesh", District = "Guntur", FactType = "SELECT", Description = "", CaseDate = "", FactNumber = "", Fact = new Fact { Id = "1"} };
var data = await client.PostAsJsonAsync("http://api.in/" + "test", model);
I think this is just a json object, you can either create a class which have the same properties of (state, district etc ..) and use json serializer
or you can create JObject using Json.Net
You can use Newtonsonft.Json to to the serializaton/deserialization job and the code will be like that.
public class Rootobject
{
[JsonProperty("State")]
public string State { get; set; }
[JsonProperty("District")]
public string District { get; set; }
[JsonProperty("Fact")]
public Fact Fact { get; set; }
[JsonProperty("Description")]
public string Description { get; set; }
[JsonProperty("CaseDate")]
public string CaseDate { get; set; }
[JsonProperty("FactNumber")]
public string FactNumber { get; set; }
[JsonProperty("FactType")]
public string FactType { get; set; }
}
public class Fact
{
[JsonProperty("Id")]
public string Id { get; set; }
}
And then, after instatiating your object, just serialize it.
Rootobject example = new Rootobject();
//Add values to the variable example.
var objectSerialized = JsonConvert.SerializeObject(example);
After that, you will have a json ready to be send wherever you want.
Just change {"Fact", "{Id,1}" } to {"Fact.Id", "1" },
I have a response from Jira API, require to be deserialized into data model:
com.atlassian.greenhopper.service.sprint.Sprint#40675167[id=10151,rapidViewId=171,state=CLOSED,name=Sprint 37.1,startDate=2015-07-30T16:00:22.000+03:00,endDate=2015-08-13T16:00:00.000+03:00,completeDate=2015-08-13T14:31:34.343+03:00,sequence=10151]
This is actually the information of current sprint for issue.
I need to deserialize it to a model like:
public class Model
{
public string name { get; set; }
...
}
I have already removed all non-required information, like com.atlassian.greenhopper.service.sprint.Sprint#40675167 using Regex pattern \[(.*?)\] so I have brackets and all inside.
Now I stopped completely trying to find the a way to convert this string to a data model.
Found the following thread at the Atlassian Answers page and there appears to be no JSON representation of that inner Object. As shown in the example from that thread:
customfield_10007:[
"com.atlassian.greenhopper.service.sprint.Sprint#a29f07[rapidViewId=<null>,state=CLOSED,name=NORD - Sprint 42,startDate=2013-07-29T06:47:00.000+02:00,endDate=2013-08-11T20:47:00.000+02:00,completeDate=2013-08-14T15:31:33.157+02:00,id=107]",
"com.atlassian.greenhopper.service.sprint.Sprint#769133[rapidViewId=<null>,state=ACTIVE,name=NORD - Sprint 43,startDate=2013-08-14T15:32:47.322+02:00,endDate=2013-08-23T15:32:47.322+02:00,completeDate=<null>,id=117]"
],
The response is indeed a JSON array, but the array itself contains CSV's, so you can make use of the following to parse that:
public class DataObject
{
public string id { get; set; }
public string rapidViewId { get; set; }
public string state { get; set; }
public string name { get; set; }
public string startDate { get; set; }
public string endDate { get; set; }
public string completeDate { get; set; }
public string sequence { get; set; }
}
public class Program
{
private const string sampleStringData =
#"[id=10151,rapidViewId=171,state=CLOSED,name=Sprint 37.1,startDate=2015-07-30T16:00:22.000+03:00,endDate=2015-08-13T16:00:00.000+03:00,completeDate=2015-08-13T14:31:34.343+03:00,sequence=10151]";
static void Main(string[] args)
{
var dataObject = new DataObject();
string[][] splitted;
var sampleWithNoBrackets = sampleStringData.Substring(1,sampleStringData.Length-2);
splitted = sampleWithNoBrackets.Split(',').Select(p => p.Split('=')).ToArray();
dataObject.id = splitted[0][1];
dataObject.rapidViewId = splitted[1][1];
dataObject.state = splitted[2][1];
dataObject.name = splitted[3][1];
dataObject.startDate = splitted[4][1];
dataObject.endDate = splitted[5][1];
dataObject.completeDate = splitted[6][1];
dataObject.sequence = splitted[7][1];
Console.ReadKey();
}
}
Here's the output for the above:
I'd like to consume a REST Api and deserialize the nested JSON Response. For that purpose I tried to create some POCO classes which represent the JSON Response [1].
The response looks like this:
{
"success": true,
"message": "OK",
"types":
[
{
"name": "A5EF3-ASR",
"title": "ITIL Foundation Plus Cloud Introduction",
"classroomDeliveryMethod": "Self-paced Virtual Class",
"descriptions": {
"EN": {
"description": "some Text null",
"overview": null,
"abstract": "Some other text",
"prerequisits": null,
"objective": null,
"topic": null
}
},
"lastModified": "2014-10-08T08:37:43Z",
"created": "2014-04-28T11:23:12Z"
},
{
"name": "A4DT3-ASR",
"title": "ITIL Foundation eLearning Course + Exam",
"classroomDeliveryMethod": "Self-paced Virtual Class",
"descriptions": {
"EN": {
"description": "some Text"
(...)
So I created the following POCO classes:
public class Course
{
public bool success { get; set; }
public string Message { get; set; }
public List<CourseTypeContainer> Type { get; set; }
}
/* each Course has n CourseTypes */
public class CourseType
{
public string Name { get; set; }
public string Title { get; set; }
public List<CourseTypeDescriptionContainer> Descriptions { get; set; }
public DateTime LastModified { get; set; }
public DateTime Created { get; set; }
}
public class CourseTypeContainer
{
public CourseType CourseType { get; set; }
}
/* each CourseType has n CourseTypeDescriptions */
public class CourseTypeDescription
{
public string Description { get; set; }
public string Overview { get; set; }
public string Abstract { get; set; }
public string Prerequisits { get; set; }
public string Objective { get; set; }
public string Topic { get; set; }
}
public class CourseTypeDescriptionContainer
{
public CourseTypeDescription CourseTypeDescription { get; set; }
}
And this is the API Code:
var client = new RestClient("https://www.someurl.com");
client.Authenticator = new HttpBasicAuthenticator("user", "password");
var request = new RestRequest();
request.Resource = "api/v1.0/types";
request.Method = Method.GET;
request.RequestFormat = DataFormat.Json;
var response = client.Execute<Course>(request);
EDIT 1: I found a Typo, the Type property in AvnetCourse should be named Types:
public List<AvnetCourseTypeContainer> Type { get; set; } // wrong
public List<AvnetCourseTypeContainer> Types { get; set; } // correct
Now the return values look like:
response.Data.success = true // CORRECT
repsonse.Data.Message = "OK" // CORRECT
response.Data.Types = (Count: 1234); // CORRECT
response.Data.Types[0].AvnetCourseType = null; // NOT CORRECT
EDIT 2: I implemented the Course.Types Property using a List<CourseType> instead of a List<CourseTypeContainer>, as proposed by Jaanus. The same goes for the CourseTypeDescriptionContainer:
public List<CourseTypeContainer> Type { get; set; } // OLD
public List<CourseTypeDescriptionContainer> Descriptions { get; set; } // OLD
public List<CourseType> Type { get; set; } // NEW
public List<CourseTypeDescription> Descriptions { get; set; } // NEW
Now the response.Data.Types finally are properly filled. However, the response.Data.Types.Descriptions are still not properly filled, since there is an additional language layer (e.g. "EN"). How can I solve this, without creating a PACO for each language?
EDIT 3: I had to add an additional CourseTypeDescriptionDetails class, where I would store the descriptive Data. In my CourseTypeDescription I added a property of the Type List for each language. Code Snippet:
public class AvnetCourseType
{
public List<CourseTypeDescription> Descriptions { get; set; }
// other properties
}
public class CourseTypeDescription
{
public List<CourseTypeDescriptionDetails> EN { get; set; } // English
public List<CourseTypeDescriptionDetails> NL { get; set; } // Dutch
}
public class CourseTypeDescriptionDetails
{
public string Description { get; set; }
public string Overview { get; set; }
public string Abstract { get; set; }
public string Prerequisits { get; set; }
public string Objective { get; set; }
public string Topic { get; set; }
}
It works now, but I need to add another property to CourseTypeDescription for each language.
OLD: The return values are
response.Data.success = true // CORRECT
repsonse.Data.Message = "OK" // CORRECT
response.Data.Type = null; // WHY?
So why does my response.Type equal null? What am I doing wrong?
Thank you
Resources:
[1] RestSharp Deserialization with JSON Array
Try using this as POCO:
public class Course
{
public bool success { get; set; }
public string message { get; set; }
public List<CourseTypeContainer> Types { get; set; }
}
Now you have list of CourseTypeContainer.
And CourseTypeContainer is
public class CourseTypeContainer
{
public CourseType CourseType { get; set; }
}
So when you are trying to get response.Data.Types[0].AvnetCourseType , then you need to have field AvnetCourseType inside CourseTypeContainer
Or I think what you want is actually this public List<CourseType> Types { get; set; }, you don't need a container there.
Just in case this helps someone else, I tried everything here and it still didn't work on the current version of RestSharp (106.6.2). RestSharp was completely ignoring the RootElement property as far as I could tell, even though it was at the top level. My workaround was to manually tell it to pull the nested JSON and then convert that. I used JSON.Net to accomplish this.
var response = restClient.Execute<T>(restRequest);
response.Content = JObject.Parse(response.Content)[restRequest.RootElement].ToString();
return new JsonDeserializer().Deserialize<T>(response);
I used http://json2csharp.com/ to create C# classes from JSON.
Then, renamed RootObject to the ClassName of the model file I'm creating
All the data in the nested json was accessible after RestSharp Deserializitaion similar to responseBody.data.Subject.Alias
where data, Subject and Alias are nested nodes inside the response JSON received.
I have a JSON string as follows:
[{
"ID":"1",
"title":"New Product Launch",
"fro":"Vitamin D",
"summary":"New Vitamin D prodcut",
"type":"image",
"link":"http:\/\/www.foo.in\/upload\/image\/1.png",
"detail":"13-11-2013",
"fileSize":23763
},
{
"ID":"2",
"title":"New Product Launch",
"fro":"Vitamin D",
"summary":"New Vitamin D prodcut",
"type":"image",
"link":"http:\/\/www.foo.in\/upload\/image\/1.png",
"detail":"13-11-2013",
"fileSize":23763
}]
My code for parsing is as follows:
AnnouncementListObject resultsJSON = JsonConvert.DeserializeObject<AnnouncementListObject>(json); //line1
using (AnnouncementDataContext context = new AnnouncementDataContext(Con_String))
{
AnnouncementData alData = new AnnouncementData();
alData.announcementID = int.Parse(resultsJSON.ID);
.
.
.
.
context.AnnouncementData.InsertOnSubmit(alData);
context.SubmitChanges();
}
EDIT:
public class AnnouncementListObject
{
public string ID { get; set; }
public string title { get; set; }
public string fro { get; set; }
public string summary { get; set; }
public string type { get; set; }
public string link { get; set; }
public string detail { get; set; }
public object fileSize { get; set; }
}
But it throws error on line 1 where I deserialize the JSON data. I want to store this multiple data rows in database. I cannot use foreach loop here as JSON data is not enclosed under root node. Any help on how should I go about?
Try deserializing to a list like so
var resultsJSON = JsonConvert.DeserializeObject<List<AnnouncementListObject>>(json); //line1
You're dealing with an array of JSON objects, but you're trying to cast it as a single object.