I've made a simple program that gets json from a website. It should give out some of the json attributes, but it doesn't do it. It simply gives me a clear String without text in it. Can someone help me?
My Code:
using System;
using System.Linq;
using System.Diagnostics;
using System.Threading;
using System.Net;
using System.IO;
using Newtonsoft.Json;
namespace ESEL_Scraper_2._0
{
class MyJsonType
{
public string title { get; set; }
public int id { get; set; }
}
class Program
{
static void Main(string[] args)
{
WebClient client = new WebClient();
client.Encoding = System.Text.Encoding.UTF8;
string site = client.DownloadString($"https://esel.at/api/termine/data?date=05.09.2020&selection=false");
var myJsonObject = JsonConvert.DeserializeObject<MyJsonType>(site);
Console.WriteLine(myJsonObject.title);
}
}
}
The JSON: https://esel.at/api/termine/data?date=05.09.2020&selection=false
MyJsonType expects the body to be like,
{
"id": 1,
"title": "title"
}
but in your case, the json is,
{
"termine": [
{ -> object }
{ -> object }
]
}
You have an array of Objects that fit into your MyJsonType. Use the following class to deserialize to
public class RootObject
{
[JsonProperty("termine")] // the name of the property is case sensetive.
public List<MyJsonType> Termine {get;set;}
}
public class MyJsonType
{
[JsonProperty("title")]
public string Title { get; set; } //C# uses uppercase first letter for properties.
[JsonProperty("id")]
public int Id { get; set; }
}
// in your main,
var obj = JsonConvert.DeserializeObject<RootObject>(json);
Console.WriteLine(obj.Termine.First().Title);
You need to structure your call as per your json string.
You class should look like this
public class ParentJsonType
{
public List<MyJsonType> termine { get; set; }
}
public class MyJsonType
{
public string title { get; set; }
public int id { get; set; }
}
and in your code you can deserialize
WebClient client = new WebClient();
client.Encoding = System.Text.Encoding.UTF8;
string site = client.DownloadString($"https://esel.at/api/termine/data?date=05.09.2020&selection=false");
var myJsonObject = JsonConvert.DeserializeObject<List<MyJsonType>>(site);
foreach(var myJosnType in myJsonObject)
{
//add your logic here
Console.WriteLine(myJosnType.title);
}
Yes, guys that already answered are absolutely right.
The point is in the wrong model you have, which has no necessary structure to contain a responded context.
The following approach is also working. The correct model for that JSON should be:
public class Termine
{
public Int64 id {get;set;}//":106102,
public String title {get;set;}//":"curated by 2020",
public String category {get;set;}//":"eSeLs Neugierde",
public String startdate {get;set;}//":"Sa, 05.09.2020",
public String startdatetime {get;set;}//":"Sa, 05.09. 11:00",
public String starttime {get;set;}//":"11:00",
public String enddate {get;set;}//":"Sa, 05.09.2020",
public List<object> runtime {get;set;}//":[ 0, "nur noch heute" ],
public String thumbnail {get;set;}//":"https:\/\/static.esel.at\/mini\/\/upload\/IpeP5wgYL7sRucTuFtpJg53zgG7hby5IiXv5txLk.jpeg",
public String thumbnail_credits {get;set;}//":null,
public String type {get;set;}//":"upcoming",
public String recommended {get;set;}//":"(Wie) Schafft's Kunst als Aktivismus in Galerier\u00e4ume?`",
public Boolean online_event {get;set;}//":false,
public String feed_urls {get;set;}//":null,
public String status {get;set;}//":"",
public String tags {get;set;}//":"Galerienfestival, internationale KuratorInnen, Aktivismus, Kunst, curatedby",
public String url {get;set;}//":"https:\/\/esel.at\/termin\/106102\/curated-by-2020",
public DateTime sort_date {get;set;}//":"2020-09-05 11:00:00",
public String sort_category {get;set;}//":"eselsneugierde",
public String location_url {get;set;}//":"https:\/\/esel.at\/location\/933\/wien",
public String location {get;set;}//":"Wien"
public override String ToString(){
return String.Format("[{0}] {1} ({2})", this.id, this.title, this.location_url);
}
}
public class Meta
{
public List<String> next {get;set;}//":[ "Sonntag,<br><nobr>06. September 2020<\/nobr>", "06.09.2020", "06092020" ],
public DateTime now {get;set;}//":"2020-09-05T18:52:05.000040Z",
public List<String> da {get;set;}//":[ "Samstag,<br><nobr>05. September 2020<\/nobr>", "05.09.2020", "05092020" ],
public DateTime end {get;set;}//":"2020-09-05T21:59:59.999999Z",
public DateTime runtime {get;set;}//":"2020-09-04T22:00:00.000000Z",
public Int32 upcoming {get;set;}//":14
public Int32 running {get;set;}//":87,
public Int64 termine {get;set;}//":16
}
public class Context
{
public List<Termine> termine{get;set;}
public Meta meta {get;set;}
}
So, your code will work with a few changes:
public static void Main(string[] args)
{
WebClient client = new WebClient()
{
Encoding = System.Text.Encoding.UTF8
};
string site = client.DownloadString("https://esel.at/api/termine/data?date=05.09.2020&selection=false");
Context ctx = JsonConvert.DeserializeObject<Context>(site);
ctx.termine.ForEach(Console.WriteLine);
}
Here is the link to the full solution where you can run and test.
https://dotnetfiddle.net/elq5Lv
Related
I'm new to c# and I have created a library that contain currency exchange rate from an API to a string
using System.Net;
namespace RateLib
{
public class CurrencyRate
{
public void getRate()
{
string url = "apikey";
WebClient myClient = new WebClient();
string txt = myClient.DownloadString(url);
}
}
}
Now, how I can put this txt string into a hashmap (if it does exist in c#) or a Dictionary ?
I think that what you want is to deserialize your json into a class containing a IDictionary for your rates. To do that we will use System.Text.Json's JsonSerializer.Deserialize.
Something like this:
public class Latest
{
public string Disclaimer { get; set; }
public string License { get; set; }
public int Timestamp { get; set; }
public string Base { get; set; }
public IDictionary<string, double> Rates { get; set; }
}
public static void Main()
{
var url = "https://openexchangerates.org/api/latest.json?app_id=69cb235f2fe74f03baeec270066587cf";
var myClient = new WebClient();
var json = myClient.DownloadString(url);
var options = new JsonSerializerOptions{PropertyNamingPolicy = JsonNamingPolicy.CamelCase};
var latest = JsonSerializer.Deserialize<Latest>(json, options);
Console.WriteLine(latest.Rates.First());
}
output
[AED, 3.6732]
Try it Online!
Last things, this apikey seems valid. You may want to change it now that it is exposed to the world.
I am a beginner in .Net framework, and I want to know how I can return a model without matching all the parameters in the json data. For example I have an unknown json coming in but I do know that there will be a "Name" and "Nickname" value, so I want to create an object model from these values.
Is this what you mean?
public class MyClass
{
public string key { get; set; }
public NameArray[] array { get; set; }
}
public class NameArray
{
public string Name { get; set; }
}
static void Main(string[] args)
{
string jsonString = "{\"key\": \"myKey\", \"array\": [{\"Name\": \"John\"},{\"Name\": \"Jack\"}]}";
var myClass = JsonSerializer.Deserialize<MyClass>(jsonString);
Console.WriteLine($"key: {myClass.key}");
Console.WriteLine($"name0: {myClass.array[0].Name}");
Console.WriteLine($"name1: {myClass.array[1].Name}");
}
You need a class that has your values and that's what JsonSerializer will use to deserialize the json string.
public class MyClass
{
public string Name { get; set; }
public string Nickname { get; set; }
}
static void Main(string[] args)
{
string jsonString = "{\"firstName\": \"ABC\", \"lastName\": \"XYZ\", \"age\": 5, \"email\":\"abcxyz #blahblah.com\", \"Name\": \"ABC XYZ\", \"Nickname\": \"AZ\"}";
var myClass = JsonSerializer.Deserialize<MyClass>(jsonString);
Console.WriteLine($"Name: {myClass.Name}");
Console.WriteLine($"Nickname: {myClass.Nickname}");
}
I am trying to retrieve a JSON list from my own API with the GetStringAsync method.
when I get it it returns as a "Result" object instead of just a string ?
Then I am trying to Deserialize the JSON array to a list but recieve an error .
This is how the returned string in the DEBUGGER looks from the HttpCLient.GetStringAsync :
"{\"Result\":[{\"id\":92,\"name\":\"Chris Hemsworth\",\"birthDate\":\"1983-8-11\",\"role\":\"Producer\",\"originalList\":null},{\"id\":90,\"name\":\"Jennifer Aniston\",\"birthDate\":\"1969-2-11\",\"role\":\"Producer\",\"originalList\":null},{\"id\":40,\"name\":\"Edward Norton\",\"birthDate\":\"1969-8-18\",\"role\":\"Writer\",\"originalList\":null}],\"Id\":71,\"Exception\":null,\"Status\":5,\"IsCanceled\":false,\"IsCompleted\":true,\"CreationOptions\":0,\"AsyncState\":null,\"IsFaulted\":false}"
the Exception im getting when trying to convert the JSON object to string:
Newtonsoft.Json.JsonSerializationException: 'Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[BuisnessLogic.Actor]' 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 'Result', line 1, position 10.'
UPDATE:
Here is the code:
var celebrities = JsonConvert.DeserializeObject<List<Actor>>(await client.GetStringAsync($"{serverAddress}/values/{GET_CELEBS_COMMAND}"));
the Actor class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BuisnessLogic
{
public class Actor
{
public int id { get; set; }
public string name { get; set; }
public string birthDate { get; set; }
public string role { get; set; }
public List<Actor> originalList { get; set; }
public Actor(string name, string birthDate, string role)
{
this.name = name;
this.birthDate = birthDate;
this.role = role;
}
public Actor()
{
}
public override string ToString()
{
return "Person: " + id + "" + name + " " + birthDate + " " + role;
}
}
}
EDIT 2 :
The Controller:
using BuisnessLogic;
using System.Web.Mvc;
namespace WebApplication12.Controllers
{
public class ValuesController : Controller
{
public ILogic _Ilogic;
public ValuesController(ILogic logic)
{
_Ilogic = logic;
}
// GET api/values
public ActionResult GetActors()
{
return Json(_Ilogic.GetAllActorsAsync(), JsonRequestBehavior.AllowGet);
}
}
}
The data management class :
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Configuration;
using System.Collections.Concurrent;
using System.Threading.Tasks;
using System.Linq;
namespace BuisnessLogic
{
public class Logic : ILogic
{
static string filePath;
private static ConcurrentDictionary<string, Actor> originalList;
const string BACKUP = #"D:\backup.txt";
static Logic()
{
originalList = new ConcurrentDictionary<string, Actor>();
filePath = ConfigurationManager.AppSettings["tempList"];
File.Copy(filePath, BACKUP, true);
SaveOriginal();
}
public async static Task<List<Actor>> GetCelebritiesInner()
{
return originalList.Values.ToList();
}
public async Task<List<Actor>> GetAllActorsAsync()
{
return await GetCelebritiesInner();
}
// Try to read the data from the Json and initialize it. if failed , initialize with whatever it got. return
private static List<Actor> ReadActorsFromJson(string json)
{
List<Actor> celebListReadFromFile;
try
{
var celebJson = File.ReadAllText(json);
celebListReadFromFile = JsonConvert.DeserializeObject<List<Actor>>(celebJson);
}
catch (Exception ex)
{
celebListReadFromFile = new List<Actor>();
// Empty list/whatever it got in it
}
return celebListReadFromFile;
}
public async Task RemoveActorAsync(string name)
{
if (originalList.TryRemove(name, out Actor removedActor))
{
var jsonToWrite = JsonConvert.SerializeObject(await GetCelebritiesInner());
try
{
File.WriteAllText(filePath, jsonToWrite);
}
catch (Exception ex)
{
//Unable to remove due to an error.
}
}
}
public async Task ResetAsync()
{
UpdateFile();
}
//Saving the actor, adding the name as key & object as value.
public static void SaveOriginal()
{
foreach (var currCeleb in ReadActorsFromJson(filePath))
{
originalList.TryAdd(currCeleb.name, currCeleb);
}
}
public static void UpdateFile()
{
File.WriteAllText(filePath, string.Empty);
var text = File.ReadAllText(BACKUP);
File.WriteAllText(filePath, text);
}
}
}
The update method that goes to the uri and gets the string :
public async void update()
{
var b = await client.GetStringAsync($"{serverAddress}/values/{GET_CELEBS_COMMAND}");
var celebrities = JsonConvert.DeserializeObject<List<Actor>>(b);
foreach (Actor actor in celebrities)
{
actorBindingSource.Add(actor);
}
}
The JSON shown in your question is a serialised instance of Task<T>, which includes properties such as Result, AsyncState and IsFaulted. It's clear that this should be a serialised instance of T (List<Actor> in your case), which usually means there's a missing await somewhere.
This "missing await" is in your ValuesController.GetActors, which is passing the result of ILogic.GetAllActorsAsync into Json. This ends up with an instance of Task<List<Actor>> being passed in, instead of just List<Actor>. In order to resolve that, use await, like this:
public async Task<ActionResult> GetActors()
{
return Json(await _Ilogic.GetAllActorsAsync(), JsonRequestBehavior.AllowGet);
}
This also requires making GetActors async, as I've shown above.
First replace **Result** with Result.
var stringResult = await HttpCLient.GetStringAsync().Replace("**Result**", "Result");
Second create the classes which has the same properties as the json result.
public class JsonResult
{
public List<ResultObject> Result { get; set; }
public int Id { get; set; }
public string Exception { get; set; }
public int Status { get; set; }
public bool IsCanceled { get; set; }
public bool IsComplete { get; set; }
public int CreationOptions { get; set; }
public string AsyncState { get; set; }
public bool IsFaulted { get; set; }
}
public class ResultObject
{
public int id { get; set; }
public string name { get; set; }
public string birthDate { get; set; }
public string role { get; set; }
public string originalList { get; set; }
}
And than deserialize the string with:
var resultObject = JsonConvert.DeserializeObject<JsonResult>(result);
And resultObject will contain the whole result.
My web service receives data-filtering values in JSON format. Here is an example of how the filtering criteria is sent:
var jsonString = {
"startDate":"2015-01-19T15:04:54.897Z",
"endDate":"2016-01-19T15:04:54.897Z",
"filterParams":{
"facilityIds":
[
{"ID":1,"charID":"1","Description":"Health Group Umbrella Organization","DoubleValue1":35.009803,"DoubleValue2":85.21,"StringValue1":""},
{"ID":2,"charID":"2","Description":"Main Hospital Organization","DoubleValue1":35.04,"DoubleValue2":89.3,"StringValue1":""},
{"ID":3,"charID":"3","Description":"Regional Medical Center","DoubleValue1":35.04,"DoubleValue2":89.30,"StringValue1":""}
],
"GenderIds":[{"ID":0,"charID":"F","Description":"Female","DoubleValue1":0,"DoubleValue2":0,"StringValue1":""}],
"AgeRangeIds":[{"ID":4,"charID":"4","Description":"30 - 34","DoubleValue1":0,"DoubleValue2":0,"StringValue1":""}],
"HomeownerIds":[{"ID":7,"charID":"7","Description":"More Likely Owner 1","DoubleValue1":0,"DoubleValue2":0,"StringValue1":""}],
"IncomeRangeIds":[{"ID":3,"charID":"3","Description":"$30,001 - $40,000","DoubleValue1":0,"DoubleValue2":0,"StringValue1":""}],
"HasChildrenIds":[{"ID":0,"charID":"N","Description":"No","DoubleValue1":0,"DoubleValue2":0,"StringValue1":null}],
"EncoutnerTypesIds":
[
{"ID":2,"charID":"2","Description":"Ambulatory","DoubleValue1":0,"DoubleValue2":0,"StringValue1":""},
{"ID":1,"charID":"1","Description":"InPatient","DoubleValue1":0,"DoubleValue2":0,"StringValue1":""},
{"ID":3,"charID":"3","Description":"Emergency","DoubleValue1":0,"DoubleValue2":0,"StringValue1":""},
{"ID":4,"charID":"4","Description":"Office Visit","DoubleValue1":0,"DoubleValue2":0,"StringValue1":""}
]
}
}
I'm able to pull out the startDate and endDate no problem:
var jsonValues = jsonSerializer.Deserialize<Dictionary<string, object>>(jsonString);
DateTime startDate = DateTime.Parse(jsonValues["startDate"] as string);
DateTime endDate = DateTime.Parse(jsonValues["endDate"] as string);
However, I just can't seem to figure out how to handle the "filterParams" portion of the JSON. It should map to the class structure:
public class FilterModel
{
public int ID { get; set; }
public char charID { get; set; }
public string Description { get; set; }
public double DoubleValue1 { get; set; }
public double DoubleValue2 { get; set; }
public string StringValue1 { get; set; }
}
the following statement populates the variable with the correct data but I'm unable to access the values.
var filterParams = jsonValues["filterParams"];
I need to somehow deserialize the data into a Dictionary<string, FilterModel> but the Deserialize method requires a string param and filterParams is an object.
You don't need to deserialize each property manually...
JavaScriptSerializer
You can deserialize it directly to a complex object using the native JavaScriptSerializer:
RootObject obj = new JavaScriptSerializer().Deserialize<RootObject>(jsonString);
Newtonsoft Json
Or as #Wobbles suggested, you can use the Json.Net also known as Newtonsoft Json:
RootObject obj = JsonConvert.DeserializeObject<RootObject>(jsonString);
It is faster and has more features than JavaScriptSerializer as you can see here.
You can use something like this (Very specific, but it must works):
-> This is using Newtonsoft
public class YourJson
{
public DateTime startDate;
public DateTime endDate;
public FilterParams filterParams;
}
public class FilterParams
{
public __ID[] facilityIds;
public __ID[] GenderIds;
public __ID[] AgeRangeIds;
public __ID[] HomeownerIds;
public __ID[] IncomeRangeIds;
public __ID[] HasChildrenIds;
public __ID[] EncoutnerTypesIds;
}
public class __ID
{
public int ID;
public char charID;
public string Description;
public double DoubleValue1;
public double DoubleValue2;
public String StringValue1;
}
var yourJson = JsonConvert.DeserializeObject<YourJson>(json);
I am querying Firebase and retrieve a collection of objects like so:
{"-K5f0ccEKkVkxTAavQKY": {
"Appeal": {
"ID": "1450273330435",
"comps": [
162248,
162272,
162273,
162281,
162544
],
"property": {
"Address": "15 Main Street",
"propID": 169729
},
"timeDateStamp": "Wed Dec 16 2015 08:42:10 GMT-0500 (Eastern Standard Time)",
"userUUID": "google:229139952703238437512",
"year": 2016
}
}}
I would like to deserialize them into objects with this definition:
public class Appeal
{
public string ID;
public List<string> comps;
public AppealProperty property;
public string timeDateStamp;
public string UUID;
public int year;
}
public class AppealProperty
{
public string address;
public string propID;
}
I have troubles getting it deserialized. I don't need the initial string (e.g. "K5f0ccEKkVkxTAavQKY"). I'm able to change the object definitions if need be. I have a feeling a Dictionary would be useful.
The quick and dirty object is to use Dictionary<string,Appeal> as your deserialization target. At that point it would be as simple as:
var firebaseLookup = JsonConvert.DeserializeObject<Dictionary<string,Appeal>>(json);
var data = firebaseLookup.Values.ToList(); // or FirstOrDefault();
This approach would also handle the case if you ever had to get multiple objects at once, and it would give you the opportunity to use that key if it turns out the key was important after all.
You could serialise your data into the classes below.
public class AppealProperty
{
public string Address { get; set; }
public int propID { get; set; }
}
public class Appeal
{
public string ID { get; set; }
public List<int> comps { get; set; }
public AppealProperty property { get; set; }
public string timeDateStamp { get; set; }
public string userUUID { get; set; }
public int year { get; set; }
}
public class FireBase
{
public Appeal Appeal { get; set; }
}
public class RootObject
{
[JsonProperty(PropertyName = " - K5f0ccEKkVkxTAavQKY")]
public FireBase FireBaseRoot
{
get;
set;
}
}
Assuming that you are using JSON.NET, you can then get the object you are after, using this snippet:
var firebaseObject = JsonConvert.DeserializeObject<RootObject>(json);
var data = firebaseObject.FireBaseRoot.Appeal;
If the root name is dynamic, as indicated by your comment, you could skip the root instead and serialise straight into the FireBase class:
JObject parsedJson = JObject.Parse(json);
var fireBase = parsedJson.First.Children().First().ToObject(typeof (FireBase));
Since I've never been able to parse a DataSnapshot with newtonSoft Json parser, I did this to build a list of object I needed to put in a ListView:
MyModelObject class
public class MyModelObject: Java.Lang.Object
{
public string Title { get; set; }
public string Description { get; set; }
public MyModelObject(){}
}
into My Listener
public void OnDataChange(DataSnapshot snapshot)
{
List<MyModelObjecct> myList = new List<MyModelObject>();
myList = databaseService
.GetMyModelObjectList(snapshot
.Children?
.ToEnumerable<DataSnapshot>());
}
Method into the DatabaseService class
public List<MyModelObject> GetMyModelObjectList(IEnumerable<DataSnapshot> enumerableSnapshot)
{
List<MyModelObject> list = new List<MyModelObject>();
foreach (var item in enumerableSnapshot)
{
list.Add(ObjectExtensions.DataSnapshotToObject<MyModelObject>(item.Children?.ToEnumerable<DataSnapshot>()));
}
return list;
}
ObjectExtensions class
public static class ObjectExtensions
{
public static T DataSnapshotToObject<T>(IEnumerable<DataSnapshot> source)
where T : class, new()
{
var someObject = new T();
var someObjectType = someObject.GetType();
foreach (var item in source)
{
someObjectType
.GetProperty(item.Key)
.SetValue(someObject, item.Value.ToString(), null);
}
return someObject;
}
}