Xamarin.Forms WebAPI JsonConverter.DeserializeObject unhandled exception - c#

I'm trying to replicate the functionality in one of MoshHamedani's course on Xamarin Forms.
Here's my code (with a valid, working _url, that returns a json object with escape characters):
public partial class PartnersListPage : ContentPage
{
private const string _url = "xyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyz";
private HttpClient _httpClient = new HttpClient();
private ObservableCollection<Partner> _partners;
public PartnersListPage()
{
InitializeComponent();
}
protected override async void OnAppearing()
{
var jsonObject = await _httpClient.GetStringAsync(_url);
var dotNetObject = JsonConvert.DeserializeObject<List<Partner>>(jsonObject);
_partners = new ObservableCollection<Partner>(dotNetObject);
partnersListView.ItemsSource = _partners;
base.OnAppearing();
}
Partner.cs looks like this:
public class Partner
{
//public int Id { get; set; }
//public string Name { get; set; }
public string ImageUrl { get; set; }
public string WebUrl { get; set; }
}
Postman returns the following:
{
"partners": [
{
"imageUrl": "http://www.abcdefgh.xy//media/1007/3.jpg",
"webUrl": "http://www.abcdefgh.xy/"
},
{
"imageUrl": "http://www.ijklmnop.xy//media/1009/5.jpg",
"webUrl": "https://www.ijklmnop.xy/xy"
},
{
"imageUrl": "http://www.qrstuvxy.xy//media/2623/slsp.svg",
"webUrl": "https://www.qrstuvxy.xy/"
}
]
}
When I hit the JsonConvert.DeserializeObject line, I get the following:
An unhandled exception occured. Why is it not working?

You are deserializing with incorrect type (List<Partner>)
I'm using Json to c# converter in order to determine the class I need - just paste in your json text/data and in will generate the classes for you. For the example for your json text/data you need:
public class Partner
{
public string imageUrl { get; set; }
public string webUrl { get; set; }
}
public class RootObject
{
public List<Partner> partners { get; set; }
}
........
var result = JsonConvert.DeserializeObject<RootObject>(jsonObject);

controller returning single object but you are trying to array deserialize
public class Partner
{
//public int Id { get; set; }
//public string Name { get; set; }
public string ImageUrl { get; set; }
public string WebUrl { get; set; }
}
public class ApiResult
{
List<Partner> Partners {get;set;}
}
and..
var dotNetObject = JsonConvert.DeserializeObject<ApiResult>(jsonObject);

Related

How to generate a JSON class with dynamic name

I don't know if there is an existing name for that case, but I'm trying to retrieve data from NASA API (https://api.nasa.gov/) and I have a simple challenge to catch a list of objects near earth. Here is the JSON response I have from the GET request I do to "https://api.nasa.gov/neo/rest/v1/feed?...."
{
"links": {
"next": "http://www.neowsapp.com/rest/v1/feed?start_date=2021-07-04&end_date=2021-07-04&detailed=false&api_key=NjgpxgSbYHXyFSBI3HaOhRowtjMZgAKv2t4DMRym",
"prev": "http://www.neowsapp.com/rest/v1/feed?start_date=2021-07-02&end_date=2021-07-02&detailed=false&api_key=NjgpxgSbYHXyFSBI3HaOhRowtjMZgAKv2t4DMRym",
"self": "http://www.neowsapp.com/rest/v1/feed?start_date=2021-07-03&end_date=2021-07-03&detailed=false&api_key=NjgpxgSbYHXyFSBI3HaOhRowtjMZgAKv2t4DMRym"
},
"element_count": 6,
"near_earth_objects": {
"2021-07-03": [
{
"links": {
"self": "http://www.neowsapp.com/rest/v1/neo/3701710?api_key=NjgpxgSbYHXyFSBI3HaOhRowtjMZgAKv2t4DMRym"
},
"id": "3701710",
"neo_reference_id": "3701710",
"name": "(2014 WF497)",
"nasa_jpl_url": "http://ssd.jpl.nasa.gov/sbdb.cgi?sstr=3701710",
"absolute_magnitude_h": 20.23,
"estimated_diameter": {
"kilometers": {
}
And that's the way it is built in Visual Studio (using the Special Paste option for JSON)
public class NearEarthObject
{
public Links links { get; set; }
public int element_count { get; set; }
public Near_Earth_Objects near_earth_objects { get; set; }
}
public class Links
{
public string next { get; set; }
public string prev { get; set; }
public string self { get; set; }
}
public class Near_Earth_Objects
{
public _20210703[] _20210703 { get; set; }
}
public class _20210703
{
public Links1 links { get; set; }
public string id { get; set; }
public string neo_reference_id { get; set; }
public string name { get; set; }
public string nasa_jpl_url { get; set; }
public float absolute_magnitude_h { get; set; }
public Estimated_Diameter estimated_diameter { get; set; }
public bool is_potentially_hazardous_asteroid { get; set; }
public Close_Approach_Data[] close_approach_data { get; set; }
public bool is_sentry_object { get; set; }
}
The question is, inside of the element "near_earth_objects", there is an element called "2021-07-03" (the date of the data I requested), the problem is that I am trying to include it into a DataGridView made in .NET C# (Windows Forms, but that doesn't matters here, I think) and the user wants to get the information by date. So, "2021-07-03" is a valid member just for one day, and the user should be able to get data from multiple days.
So, is there a way in C# to get all child objects inside of near_earth_objects without knowing their names since there will be the option to search for asteroids from date X to Y in my application?
Using System.Text.Json
The API response will map to the following classes
public class Neo
{
public Links Links { get; set; }
public int ElementCount { get; set; }
public Dictionary<string, List<NearEarthObject>> NearEarthObjects { get; set; }
}
public class Links
{
public string Next { get; set; }
public string Prev { get; set; }
public string Self { get; set; }
}
public class NearEarthObject
{
public Links Links { get; set; }
public string Id { get; set; }
public string Name { get; set; }
// Other properties
}
The NearEarthObjects is simply a Dictionary, where the key is the formatted date and value is a List containing NearEarthObject
The PropertyNamingPolicy will allow us to support the API's underscore property naming convention.
public class UnderscoreNamingPolicy : JsonNamingPolicy
{
public override string ConvertName(string name)
{
return name.Underscore();
}
}
Example usage
// using using System.Text.Json;
var response = await new HttpClient().GetStringAsync(url);
var neo = JsonSerializer.Deserialize<Neo>(response, new JsonSerializerOptions
{
PropertyNamingPolicy = new UnderscoreNamingPolicy()
});
foreach(var neos in neo.NearEarthObjects)
{
Console.WriteLine(neos.Key);
}
use System.Text.Json, JsonNamingPolicy
demo code
public class DynamicNamePolicy : JsonNamingPolicy
{
public override string ConvertName(string name)
{
var today = DateTime.Today.ToString("yyyy-MM-dd");
if (name.Equals("DateData")) //model property name
return today; //convert to json string property name
return name;
}
}
//data deserialize
string data = ""; //json string
var obj = JsonSerializer.Deserialize<NearEarthObject>(data, new JsonSerializerOptions
{
PropertyNamingPolicy = new DynamicNamePolicy(),
});

Parse Json Response Data

I am calling a Solr Apache search url and it turns Json data format. However, when I parse the Json, I receive null data. My Json format is like below:
responseHeader:
status: 0
QTime: 1
params:
q: "mykeyword"
response:
numFound: 67
start: 0
docs:
0:
tstamp: "xxxxx.xxxx.xxxx"
digest: "xxxxxxxxxxxxxxx"
boost: 0.010186654
id: "https://myserer/faq.html"
title: "xxxx"
url: "xxxxxx"
_version_:"xxxxxx"
content: "xxxxxxxxxx"
1:
tstamp: "xxxx"
.....
so I created dataModel to map the json data format:
public class ResponseModel
{
public ResponseHeader responseheader { get; set; }
public Response_ responsedata { get; set; }
}
public class Response_
{
public int numFound { get; set; }
public int start { get; set; }
public Doc doc { get; set; }
}
public class Params
{
public string q { get; set; }
}
public class Page
{
public string tstamp { get; set; }
public string digest { get; set; }
public string boost { get; set; }
public string id { get; set; }
public string title { get; set; }
public string url { get; set; }
public string _version_ { get; set; }
public string content { get; set; }
}
public class Doc
{
public List<Page> pages { get; set; }
}
my code to retrieve json search results:
string baseURL = "http://myserver:8983/solr/nutch/select?q=" + keyword;
string responseBody = string.Empty;
keyword = Request.Form["txtSearchTerm"];
if (!string.IsNullOrEmpty(keyword))
{
responseBody = getJSONString(baseURL);
}
var myData = JsonConvert.DeserializeObject<ResponseModel>(responseBody);
var Response = myData.responsedata.doc; //The Response is null here
// ...
private static string getJSONString(string apiURL)
{
// it returns json string
}
Where is the problem? BTW, there are a lot of \n line break in the json data. Is that the problem and how to deal with it? Thanks
add json data sample below:
{
"responseHeader": {
"status": 0,
"QTime": 0,
"params": {
"q": "Intranet"
}
},
"response": {
"numFound": 19,
"start": 0,
"docs": [
{
"tstamp": "2020-05-20T01:23:56.427Z",
"digest": "d615d21052125d3023a6ea5a244a6be0",
"boost": 0.043801095,
"id": "https://myserver/services/index.html",
"title": "Office of Services",
"url": "https://myserver/services/index.html",
"content": "Office of Services\nWelcome to the xxxx Website\nAccessibility Navigation:\nSkip to the header\nSkip to the main content\nSkip to the footer\nIt appears that you are viewing this site with an outdated browser.\nUpdate your browser for the best viewing experience by downloading the latest version below:\nInternet Explorer\nGoogle Chrome\nFirefox\nSafari\nMenu\nSearch\nSearch\n ...\nTop\n",
"_version_": 1667170768636608512
},
{
"tstamp": "2020-05-20T01:23:56.426Z",
"digest": "16cc4c01acd01d15ddbc59b7d43b435f",
"boost": 0.045213405,
"id": "https://myserver/media/index.html",
"title": "Library Technical",
"url": "https://myserver/media/index.html",
"content": "Library Technical Services Website\nAccessibility Navigation:\nSkip to the header\nSkip to the main content\nSkip to the footer\nIt appears that you are viewing this site with an outdated browser.\nUpdate your browser for the best viewing experience by downloading the latest version below:\nInternet Explorer\nGoogle Chrome\nFirefox\nSafari\nMenu\nSearch\nSearch\n ... INTRANET\Top\n",
"_version_": 1667170768619831298
}
]
}
}
The problem is that you have an object in your json namely response and in your c# classes, you have created the property named responseData which won't map because they differ in the name, Either you would have to set the JsonProperty name to response or you should entirely change the name of your property to response. Besides, there is a web application that will correctly parse your json and will generate the C# classes for you relevantly. Here is the code that I have generated for you for the response you have shared:
public partial class WebRequestResult
{
[JsonProperty("responseHeader")]
public ResponseHeader ResponseHeader { get; set; }
[JsonProperty("response")]
public Response Response { get; set; }
}
public class Response
{
[JsonProperty("numFound")]
public long NumFound { get; set; }
[JsonProperty("start")]
public long Start { get; set; }
[JsonProperty("docs")]
public List<Doc> Docs { get; set; }
}
public class Doc
{
[JsonProperty("tstamp")]
public DateTimeOffset Tstamp { get; set; }
[JsonProperty("digest")]
public string Digest { get; set; }
[JsonProperty("boost")]
public double Boost { get; set; }
[JsonProperty("id")]
public Uri Id { get; set; }
[JsonProperty("title")]
public string Title { get; set; }
[JsonProperty("url")]
public Uri Url { get; set; }
[JsonProperty("content")]
public string Content { get; set; }
[JsonProperty("_version_")]
public double Version { get; set; }
}
public class ResponseHeader
{
[JsonProperty("status")]
public long Status { get; set; }
[JsonProperty("QTime")]
public long QTime { get; set; }
[JsonProperty("params")]
public Params Params { get; set; }
}
public class Params
{
[JsonProperty("q")]
public string Q { get; set; }
}
And you should parse your json data to C# like this:
var myData = JsonConvert.DeserializeObject<WebRequestResult>(responseBody);
You can generate your C# classes from app.quicktype.io

Deserialization of web api

Im trying to parse JSON into ListView, but its giving me deserialization error.
This is my model - it's same as api's keys:
public class Currency
{
public string Drzava { get; set; }
public int Sifra_valute { get; set; }
public string Drzava_iso { get; set; }
public int Jedinica { get; set; }
public double Kupovni_tecaj { get; set; }
public double Srednji_tecaj { get; set; }
public double Prodajni_tecaj { get; set; }
}
This is my list of Currencies:
public class CurrencyTable
{
public List<Currency> Results { get; set; }
}
Class for binding with Listview:
public class ShowCurrency
{
static ShowCurrency() {
using (var webClient = new WebClient())
{
String rawJSON =
webClient.DownloadString("http://api.hnb.hr/tecajn/v2/");
CurrencyTable currencyTable =
JsonConvert.DeserializeObject<CurrencyTable>(rawJSON);
}
}
private static List<Currency> currencies;
public static List<Currency> Currencies { get; set; }
public static List<Currency> GetCurrencies() {
return Currencies;
}
}
And i get error at: CurrencyTable currencyTable =
JsonConvert.DeserializeObject(rawJSON);
this is how api looks like:
http://api.hnb.hr/tecajn/v2
The web-service response body starts with this text:
[{"broj_tecajnice":"85","datum_primjene":"2019-05-...
Note how it starts with [ which means it's returning a JSON array directly as its root object and that it is not returning an object with a member named Results (i.e. it is not returning { Results: [ {"broj_tecajnice"... }, { ... } ] }.
Change your code to this:
List<Currency> list = JsonConvert.DeserializeObject<List<Currency>>( rawJSON );
CurrencyTable currencyTable = new CurrencyTable()
{
Results = list
};

Create a JSON string in C#

I'm trying to create an object to be returned as JSON for my REST Web Service.
I wish to get something returned like this:
{
"message": [
{
"name": "whatever.bmp"
}
],
"errors": null,
"FileInflected": 0,
"path": "C:\thepath"
}
So, how can I change the class (eFileOutput) in C#?
How can I change the class I have below?
Currently I'm able to create similar output like this:
{
"message": "Hello World",
"errors": null,
"FileInfected": 0,
"path": "C:\bla bla..."
}
and my C# class is as follows:
[DataContract]
public class eFileOutput
{
[DataMember]
public string message { get; set; }
[DataMember]
public string errors { get; set; }
[DataMember]
public Int32 FileInfected { get; set; }
[DataMember]
public string path { get; set; }
}
Tks
This is the classes that represent the JSON you've stated:
public class Message
{
public string name { get; set; }
}
public class MyObject
{
public List<Message> message { get; set; }
public object errors { get; set; }
public int FileInflected { get; set; }
public string path { get; set; }
}
var json = Newtonsoft.Json.JsonConvert.SerializeObject(new MyObject
{
message = new List<Message>
{
new Message {name = "whatever.bmp"}
},
FileInflected = 0,
path = #"c:\thepath"
});
Edit (thanks to devzero): Then you can serialize using Newtonsoft (my favorite) or JavaScriptSerializer as stated here: Turn C# object into a JSON string in .NET 4
public class MyObject
{
public Message Message { get; set; }
public List<Error> Errors { get; set; }
public int FileInflected { get; set; }
public string Path { get; set; }
}
public class Message
{
public string Name { get; set; }
}
public class Error
{
//Whatever you want
}
and if You want to serialize member as camelCase, describe like this:
var jsonSerializerSettings = new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() };
var json = JsonConvert.SerializeObject(c, jsonSerializerSettings);

all values not coming while parsing json to string in c#

i have j son data in string in j son response. I'm able to get only request-id value. other are coming in debugging but unable to retrieve from dictionary type.can u tell me how to get other values of a mobile number- date , status and description.
screen shot added kindly go through it http://postimg.org/image/6iad15yxl/
my j son data
{
"requestId": "546b384ce51f469a2e8b4567",
"numbers": {
"917566551111": {
"date": "2014-11-18 17:45:59",
"status": 1,
"desc": "DELIVERED"
}
}
}
C# code
public partial class jsontoCsharp : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
json = Request.QueryString["data"];
var req = JsonConvert.DeserializeObject<Request>(json);
string requestid = req.requestId;
}
}
public class smsstatus
{
public string date { get; set; }
public int status { get; set; }
public string desc { get; set; }
}
public class Request
{
public string requestId { get; set; }
public Dictionary<string, smsstatus> numbers { get; set; } //<-- See this line
}
Your model should be something like this
public class smsstatus
{
public string date { get; set; }
public int status { get; set; }
public string desc { get; set; }
}
public class Request
{
public string requestId { get; set; }
public Dictionary<string, smsstatus> numbers { get; set; } //<-- See this line
}
Now these deserializations will work
var req = JsonConvert.DeserializeObject<Request>(json);
or
var req = new JavaScriptSerializer().Deserialize<Request>(json);
As your Json is quite complex, try as following..
var results = JsonConvert.DeserializeObject<dynamic>(json);
var result is containing your deserialized json now you can access the results object using dot (.) notation

Categories

Resources