Deserialize Json C# error - c#

Well, I'm new to programming, and I have a problem.
This is my class Valores
public class Valores
{
[JsonProperty("nome")]
public string Nome { get; set; }
[JsonProperty("valor")]
public double Valor { get; set; }
[JsonProperty("ultima_consulta")]
public int UltimaConsulta { get; set; }
[JsonProperty("fonte")]
public string Fonte { get; set; }
}
And this is my method where I get and deserialize my Json
public static async Task<Valores> GetAsync()
{
Valores valores = null;
using (var client = new HttpClient())
{
var json = await client.GetStringAsync("http://api.promasters.net.br/cotacao/v1/valores");
valores = JsonConvert.DeserializeObject<Valores>(json);
}
return valores;
}
This is json that the way: "http://api.promasters.net.br/cotacao/v1/valores" returns.
{
"status": true,
"valores": {
"USD": {
"nome": "Dólar",
"valor": 3.0717,
"ultima_consulta": 1490040302,
"fonte": "UOL Economia - http://economia.uol.com.br/"
},
"EUR": {
"nome": "Euro",
"valor": 3.3002,
"ultima_consulta": 1490040302,
"fonte": "UOL Economia - http://economia.uol.com.br/"
},
"ARS": {
"nome": "Peso Argentino",
"valor": 0.1965,
"ultima_consulta": 1490040302,
"fonte": "UOL Economia - http://economia.uol.com.br/"
},
"GBP": {
"nome": "Libra Esterlina",
"valor": 3.7966,
"ultima_consulta": 1490040302,
"fonte": "UOL Economia - http://economia.uol.com.br/"
},
"BTC": {
"nome": "Bitcoin",
"valor": 3472,
"ultima_consulta": 1490067603,
"fonte": "Mercado Bitcoin - http://www.mercadobitcoin.com.br/"
}
}
}
I do not know what I did wrong, because this
var json = await client.GetStringAsync("http://api.promasters.net.br/cotacao/v1/valores");
It was to receive Json in string, but is not receiving anything, it's like an empty string.

I experimented a bit, and it appears the web site requires the user agent request string to be set to something in order for JSON to be returned. And, by something, I mean that the string "something" seems to work, as does the string "Wget/1.11.4". You should check the documentation (Portugese) to make sure there are no restrictions on programmatic access to this site, and comply with those access restrictions (if any).
Also, your data model does not reflect your JSON. You need a higher level root object as follows:
public class RootObject
{
public RootObject() { this.valores = new Dictionary<string, Valores>(); }
public bool status { get; set; }
public Dictionary<string, Valores> valores { get; set; }
}
Here is a sample fiddle that successfully downloads and deserializes JSON from the site by setting the user agent. It uses WebClient since that's what seems to be available on https://dotnetfiddle.net/:
public static async Task<RootObject> GetAsync()
{
using (var client = new WebClient())
{
client.Headers["User-Agent"] = "something";
var json = await client.DownloadStringTaskAsync(#"http://api.promasters.net.br/cotacao/v1/valores");
var root = JsonConvert.DeserializeObject<RootObject>(json);
return root;
}
}
And for HttpClient I think it should be (untested):
public static async Task<RootObject> GetAsync()
{
var client = new HttpClient();
client.DefaultRequestHeaders.Add("User-Agent", "something");
var json = await client.GetStringAsync("http://api.promasters.net.br/cotacao/v1/valores");
return JsonConvert.DeserializeObject<RootObject>(json);
}
See also this post for a discussion of whether to dispose the HttpClient.

There issue here is that the deserialised json is not correctly getting mapped to a an object. Try to create a wrapper class over your model (Valores) and then try to map.
public class Valores
{
[JsonProperty("nome")]
public string Nome { get; set; }
[JsonProperty("valor")]
public double Valor { get; set; }
[JsonProperty("ultima_consulta")]
public int UltimaConsulta { get; set; }
[JsonProperty("fonte")]
public string Fonte { get; set; }
}
public class ValoresList
{
public boolean status { get; set; }
public Valores USD { get; set; }
public Valores EUR { get; set; }
public Valores ARS { get; set; }
public Valores GBP { get; set; }
public Valores BTC { get; set; }
}
And then map the wrapper class to the deserialised json.
public static async Task<ValoresList> GetAsync()
{
ValoresList valores = null;
using (var client = new HttpClient())
{
var json = await client.GetStringAsync("http://api.promasters.net.br/cotacao/v1/valores");
valores = JsonConvert.DeserializeObject<ValoresList>(json);
}
return valores;
}

The problem is the json returned contains a collection of Valores in a dictionary, you're trying to map the response to a single Valore object.
Your container wants to look like this. The key for the dictionary is the string representation of the currency.
class Container
{
public bool Status { get; set; }
public Dictionary<string, ValorInfo> Valores { get; set; }
}
Your Valor class is good as is, I renamed it to prevent a conflict on the class name to Valor property.
class ValorInfo
{
[JsonProperty("nome")]
public string Nome { get; set; }
[JsonProperty("valor")]
public double Valor { get; set; }
[JsonProperty("ultima_consulta")]
public int UltimaConsulta { get; set; }
[JsonProperty("fonte")]
public string Fonte { get; set; }
}
Finally this is how you use it, props to #dbc for spotting the user-agent requirement, that had me stumped!
async void Main()
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Accept", "application/json");
client.DefaultRequestHeaders.Add("User-Agent", "linqpad");
var response = await client.GetAsync("http://api.promasters.net.br/cotacao/v1/valores");
response.EnsureSuccessStatusCode();
var container = await response.Content.ReadAsAsync<Container>();
// do stuff with container...
}
}

Related

How to use class object instead of using JObject in .NET Core

I want to return C# class object instead of using JObject in here. Could someone can tell me how to use it.
private async Task<JObject> GetReceiptById(string Id, string name)
{
var response = await _ApiService.Get(Id, name);
var responseStr = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
return JObject.Parse(responseStr);
}
throw new Exception(responseStr);
}
this method is return (return JObject.Parse(responseStr)); below JSON output. for that how to create a new class. I am not sure how to apply all in one class.
{
"receipts": [
{
"ReceiptHeader": {
"Company": "DHSC",
"ErpOrderNum": "730",
"DateTimeStamp": "2022-05-14T13:43:57.017"
},
"ReceiptDetail": [
{
"Line": 1.0,
"ITEM": "PP1016",
"ITEM_NET_PRICE": 0.0
},
{
"Line": 2.0,
"ITEM": "PP1016",
"ITEM_NET_PRICE": 0.0
}
],
"XrefItemsMapping": [],
"ReceiptContainer": [],
"ReceiptChildContainer": [],
"rPrefDO": {
"Active": null,
"AllowLocationOverride": null,
"DateTimeStamp": null
}
}
]
}
You can bind the Response Content to a known Type using ReadAsAsync<T>().
https://learn.microsoft.com/en-us/previous-versions/aspnet/hh835763(v=vs.118)
var result = await response.Content.ReadAsAsync<T>();
In your example you will also run into further issues as you are not closing your response after getting it from the Api Service Get method.
Below is a possible solution where you send your object type to the Get method. (not tested)
public virtual async Task<T> GetApiCall<T>(Id, name)
{
//create HttpClient to access the API
var httpClient = NewHttpClient();
//clear accept headers
httpClient.DefaultRequestHeaders.Accept.Clear();
//add accept json
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
//return the client for use
using (var client = await httpClient )
{
//create the response
HttpResponseMessage response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
//create return object
try
{
var result = await response.Content.ReadAsAsync<T>();
//dispose of the response
response.Dispose();
return result;
}
catch
{
throw;
}
}
// do something here when the response fails for example
var error = await response.Content.ReadAsStringAsync();
//dispose of the response
response.Dispose();
throw new Exception(error);
}
}
What you probably looking for is Deserialization
you can achieve it with
var model = JsonConvert.Deserialize<YourClass>(responseStr);
return model;
but the class (YourClass) properties must match the json string you provided in responseStr.
As the comments section you asked for a generated class:
here is what should look like, after you generate the class.
Note: most of the times, you will need to edit the generated class.
// Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(myJsonResponse);
public class Receipt
{
public ReceiptHeader ReceiptHeader { get; set; }
public List<ReceiptDetail> ReceiptDetail { get; set; }
public List<object> XrefItemsMapping { get; set; }
public List<object> ReceiptContainer { get; set; }
public List<object> ReceiptChildContainer { get; set; }
public RPrefDO rPrefDO { get; set; }
}
public class ReceiptDetail
{
public double Line { get; set; }
public string ITEM { get; set; }
public double ITEM_NET_PRICE { get; set; }
}
public class ReceiptHeader
{
public string Company { get; set; }
public string ErpOrderNum { get; set; }
public DateTime DateTimeStamp { get; set; }
}
public class Root
{
public List<Receipt> receipts { get; set; }
}
public class RPrefDO
{
public object Active { get; set; }
public object AllowLocationOverride { get; set; }
public object DateTimeStamp { get; set; }
}
generated by: https://json2csharp.com/

Convert JsonPatchDocument to string C#

I am using Newtonsoft.Json.JsonConvert.SerializeObject to convert a JsonPatchDocument<T> to string but it's value property (which is in JObject format) doesn't seem to be converted to string.
Here is what it looks like:
Here is the JSON I am using to create patchDocument object
[
{
"path": "/expenseLines/",
"op": "ReplaceById",
"value": {
"ExpenseLineId": 1,
"Amount": 4.0,
"CurrencyAmount": 4.0,
"CurrencyCode": "GBP",
"ExpenseDate": "2021-11-01T00:00:00",
"ExpenseType": "TAXI"
}
}
]
This JSON is successfully deserialized to JsonPatchDocument object but when I try to serialize it back to JSON, I lose value property (as shown in the picture by red arrows).
Any help would be appreciated :)
I can't reproduce your problem, can you provide more information? I got stuck during your second serialization. But I used using System.Text.Json to complete your needs, you can look at:
Model:
public class Test
{
public string path { get; set; }
public string op { get; set; }
public TestValue testValue { get; set; } = new TestValue();
}
public class TestValue
{
public int ExpenseLineId { get; set; }
public double Amount { get; set; }
public double CurrencyAmount { get; set; }
public string CurrencyCode { get; set; }
public DateTime ExpenseDate { get; set; }
public string ExpenseType { get; set; }
}
TestController:
[ApiController]
public class HomeController : Controller
{
[Route("test")]
public Object Index()
{
var patchDocument = new Test();
patchDocument.path = "/expenseLines/";
patchDocument.op = "ReplaceById";
patchDocument.testValue.ExpenseLineId = 1;
patchDocument.testValue.Amount = 4.0;
patchDocument.testValue.CurrencyAmount = 4.0;
patchDocument.testValue.CurrencyCode = "GBP";
patchDocument.testValue.ExpenseDate = DateTime.Now;
patchDocument.testValue.ExpenseType = "TAXI";
var options = new JsonSerializerOptions { WriteIndented = true };
// var content = JsonConvert.SerializeObject(patchDocument);
// string content1 = JsonConvert.SerializeObject(patchDocument.Operations);
string jsonString = System.Text.Json.JsonSerializer.Serialize<Test>(patchDocument);
string jsonString1 = System.Text.Json.JsonSerializer.Serialize(patchDocument, options);
return jsonString;
}
Result:
Hope this helps you too.

Deserialize JSON property starting with #

Im writing a c# console app, where i need get som JSON date from a webapi.
For the most part this works fine, however in one of my JSON responses i get a property name staring with #. I cant seem to figure out how to put that JSON property into a C# object.
My code look as follows:
public class AlertResponse
{
public string #class { get; set; }
public string result { get; set; }
public string info { get; set; }
}
public class AuthenticationResponse
{
public string Access_token { get; set; }
}
class Test
{
private static HttpClient client = new HttpClient();
private static string BaseURL = "https://xxxxx.xxxx";
public void Run()
{
client.BaseAddress = new Uri(BaseURL);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
AuthenticationResponse authenticationResponse = Login();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authenticationResponse.Access_token);
AlertResponse OpenAlerts = GetOpenAlerts();
}
internal AlertResponse GetOpenAlerts()
{
var response = client.GetAsync("/api/v2/xxxxxxxxxxxxxxxxxx/alerts/open").Result;
if (response.IsSuccessStatusCode)
{
return response.Content.ReadAsAsync<AlertResponse>().Result;
}
else
{
Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);
}
return null;
}
private AuthenticationResponse Login()
{
string apiKey = "gdfashsfgjhsgfj";
string apiSecretKey = "sfhsfdjhssdjhsfhsfh";
var byteArray = new UTF8Encoding().GetBytes("public-client:public");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
var form = new FormUrlEncodedContent(new Dictionary<string, string> { { "username", apiKey }, { "password", apiSecretKey }, { "grant_type", "password" } });
HttpResponseMessage tokenMessage = client.PostAsync("/auth/oauth/token", form).Result;
if (tokenMessage.IsSuccessStatusCode)
{
return tokenMessage.Content.ReadAsAsync<AuthenticationResponse>().Result;
}
else
{
Console.WriteLine("{0} ({1})", (int)tokenMessage.StatusCode, tokenMessage.ReasonPhrase);
}
return null;
}
}
And the JSON i get looks like this:
"AlertResponse": {
"#class": "patch_ctx",
"patchUid": "afdhgfhjdajafjajadfjadfjdj",
"policyUid": "dsgafdhasfjafhdafhadfh",
"result": "0x80240022",
"info": "fdgdfhsfgjh"
}
How can i fix this?
Best regards
Glacier
Are you using Newtonsoft.Json or System.Text.Json?
In either cases you should decorate the #class Property with
//System.Text.Json
[JsonPropertyName("#class")]
public string class { get; set; }
or
//Newtonsoft.Json
[JsonProperty("#class")]
public string class { get; set; }
I guess you are looking for DataMemberAttribute and DataContract
using System.Runtime.Serialization;
[DataContract]
public class AlertResponse
{
[DataMember(Name = "#class")]
public string Class { get; set; }
[DataMember(Name = "result")]
public string Result { get; set; }
[DataMember(Name = "info")]
public string Info { get; set; }
}

How i can convert this JSON to Object in C#?

for two days I have been trying to understand how to move this JSON to an object in C#. I read a lot of topics and tried several ways to solve my problem, but still haven't solved it.
My JSON looks like this (cropped).
{
"data": [{
"id": 5643793,
"title": "It's a Title",
"description": "It's a Description.",
"tags": "#tag1 #tag2 #tag3 #tag4",
"source_url": "https:\/\/p.dw.com\/p\/3geny",
"vote_count": 120,
"bury_count": 17,
"comments_count": 33,
"related_count": 0,
"date": "2020-08-10 09:43:32",
"author": {
"login": "lnwsk",
"color": 2,
"avatar": "https:\/\/www.api.page.com\/cdn\/c3397992\/lnwsk_MfQz8MEQb2,q150.jpg"
},
"preview": "https:\/\/www.api.page.com\/cdn\/c3397993\/link_1597045214DgzqxRGEmy2UlpPZwaWfhI,w104h74.jpg",
"plus18": false,
"status": "promoted",
"can_vote": true,
"is_hot": false
}],
"pagination": {
"next": "https:\/\/api.page.com\/links\/promoted\/appkey\/X*******4y\/page\/2\/"
}
}
As you can see, there is an "element within an element" here (eg author or pagination (eg pagination I would like to get rid of)) and that is what gives me the most problem.
Here is my class where I have all the code to read the API:
using Newtonsoft.JSON;
public class PageAPI
{
public class Product
{
public string[] title { get; set; }
public double[] description { get; set; }
public string[] tags { get; set; }
public string[] source_url { get; set; }
public string[] vote_count { get; set; }
public string[] bury_count { get; set; }
public string[] comments_count { get; set; }
public string[] related_count { get; set; }
public string[] date { get; set; }
}
public async Task<Product> GetDataAsync()
{
string url = "https://api.page.com/";
string apisign = "6*********c1fe49a23f19ad6b2";
string requestParams = "links/promoted/appkey/X*******y";
Product obj = null;
// HTTP GET.
using (var client = new HttpClient())
{
// Setting Base address.
client.BaseAddress = new Uri(url);
// Setting content type.
client.DefaultRequestHeaders.Add("apisign", apisign);
// Initialization.
HttpResponseMessage response = new HttpResponseMessage();
// HTTP GET
response = await client.GetAsync(requestParams).ConfigureAwait(false);
// Verification
if (response.IsSuccessStatusCode)
{
try
{
// Reading Response.
string result = response.Content.ReadAsStringAsync().Result;
obj = JsonConvert.DeserializeObject<Product>(result);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
MessageBox.Show(ex.Message);
}
}
else
{
obj = null;
}
}
return obj;
}
}
in the Form where I want to get data from the "PageAPI" class I have:
private async void Form1_LoadAsync(object sender, EventArgs e)
{
var task = api.GetMainAsync();
task.Wait();
var data = task.Result;
label1.Text = data.title[0];
}
And... this doesn't works - on label1.Text = data.title[0]; i get error PageAPI.Product.title.get returned null
Thanks for any help!
You are missing the Root class that has "data" and "pagination" properties. Create Root class and deserialize to it and then get the data you need. Also, your Product class will have only strings.. not string[].
public class RootObject
{
public List<Product> data { get; set; }
}
public class Product
{
public string title { get; set; }
public double description { get; set; }
public string tags { get; set; }
public string source_url { get; set; }
public string vote_count { get; set; }
public string bury_count { get; set; }
public string comments_count { get; set; }
public string related_count { get; set; }
public string date { get; set; }
}
// and deserialize it
var rootObj = JsonConvert.DeserializeObject<RootObject>(result);
obj = rootObj.data.FirstOrDefault();
data object is an array ... you can loop through it to work with All the items. In above example, i used FirstOrDefault() to get the first item from the object.
Also note that when you access this data, you would not access it via [0]. Simply use
label1.Text = data.title;
Side Note
If you want the pagination property as well, create another class to get the name from pagination object.
public class RootObject {
public List<Product> data {get;set;}
public Pagination pagination {get;set;}
}
public class Pagination {
public string next {get;set; }
}
and when you deserialize your json, you would access the pagination by using,
Console.WriteLine(rootObj.pagination.next); // prints the url
How to get All the Product Names displayed
This is how you would go about getting a list of All the titles in the data object.
foreach (var product in rootObj.data)
{
Console.WriteLine(product.title);
Console.WriteLine(product.description);
Console.WriteLine(product.vote_count); // etc.
}
// Or you can create a list of all the titles from the rootObj using LINQ
List<string> allTitles = rootObj.data.Select(x => x.title).ToList();
I am not sure what you intend to do with the data you get... so not sure how to explain that piece.. but above example should give you an idea on how to iterate through all the products in the data object.

complex JSON schema .. help

"responseCode": String
"responseMessage": String
"responseBody": { "conversations": [
{
"conversationId": String,
"state": String,
"conversationType": String,
"mediaType": Enum,
"startDate":Integer,
"duration": Integer,
"tags":[{ "tagName":String,
"tagType":String,
"tagCreateDate":Integer,
"tagOffset":Integer
}],
]}
This schema continues, but my question regarding the first section applies to the rest...
How can I deserialize a JSON response based on this schema into .NET objects? what would the .NET object look like?
Is there another way to read it ? (like a .NET Dataset type of way?)
Thanks. Roey.
If you want (or have to) to use JavaScriptSerializer the code could look like following:
using System;
using System.Collections.Generic;
using System.Web.Script.Serialization;
namespace JsonSer {
public class MyTag {
public string tagName { get; set; }
public string tagType { get; set; }
public long tagCreateDate { get; set; }
public int tagOffset { get; set; }
}
public enum MyMedia {
Diskette,
UsbStick,
Disk,
Internet
}
public class MyConversation {
public string conversationId { get; set; }
public string state { get; set; }
public string conversationType { get; set; }
public MyMedia mediaType { get; set; }
public long startDate { get; set; }
public int duration { get; set; }
public List<MyTag> tags { get; set; }
}
public class MyConversations {
public List<MyConversation> conversations { get; set; }
}
public class MyData {
public string responseCode { get; set; }
public string responseMessage { get; set; }
public MyConversations responseBody { get; set; }
}
class Program {
static void Main (string[] args) {
MyData data = new MyData () {
responseCode = "200",
responseMessage = "OK",
responseBody = new MyConversations () {
conversations = new List<MyConversation> () {
new MyConversation() {
conversationId = "conversation1",
state = "state1",
conversationType = "per JSON",
mediaType = MyMedia.Internet,
startDate = DateTime.Now.Ticks,
duration = 12345,
tags = new List<MyTag>() {
new MyTag() {
tagName = "tagName1",
tagType = "tagType1",
tagCreateDate = DateTime.Now.Ticks,
tagOffset = 1
}
}
}
}
}
};
Console.WriteLine ("The original data has responseCode={0}", data.responseMessage);
JavaScriptSerializer serializer = new JavaScriptSerializer ();
string json = serializer.Serialize (data);
Console.WriteLine ("Data serialized with respect of JavaScriptSerializer:");
Console.WriteLine (json);
MyData d = (MyData)serializer.Deserialize<MyData> (json);
Console.WriteLine ("After deserialization responseCode={0}", d.responseMessage);
}
}
}
the corresponding JSON data will be look like
{
"responseCode": "200",
"responseMessage": "OK",
"responseBody": {
"conversations": [
{
"conversationId": "conversation1",
"state": "state1",
"conversationType": "per JSON",
"mediaType": 3,
"startDate": 634207605160873419,
"duration": 12345,
"tags": [
{
"tagName": "tagName1",
"tagType": "tagType1",
"tagCreateDate": 634207605160883420,
"tagOffset": 1
}
]
}
]
}
}
You can easy modify the code if you decide to use DataContractJsonSerializer.
First you can beautify all your JSON using http://jsbeautifier.org/ to make it more readable, and then the only way I know is to just go through every property step by step and create classes for them. You should add the [DataContract] attribute for classes and the [DataMember] attribute for properties.
Example
[DataContract]
public class Response{
[DataMember]
public string responseCode {get;set;}
[DataMember]
public string responseMessage {get;set;}
[DataMember]
public ResponseBody responseBody {get;set;}
}
Automatic generation of these classes
There are alternatives for XMLSerialization (using XSD) but as far as I know there are no similar solutions for json thus far.
To finally deserialize the json into .NET object you can use the following code:
Response myResponse = new Person();
MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(json));
System.Runtime.Serialization.Json.DataContractJsonSerializer serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(myResponse.GetType());
myResponse = serializer.ReadObject(ms) as Response;
ms.Close();
Where Response would be the type of object that represents the root of your json.
For more information visit the MSDN page of the DataContractJsonSerializer class.

Categories