-1

I am use api use variable date whene date change the object name change like this if i have to get data of this day i use this :https://api.covid19tracking.narrativa.com/api/2020-11-05/country/us and the result of json object is like this :this is the result

and if i have to choose other date i change the date and the variable of date object is change like this if i have to get data of 2020-10-11 ,i calll this: https://api.covid19tracking.narrativa.com/api/2020-11-05/country/us , and this is image show the result and the change of object date this is the second result

the problem is if i deserialize the api i get result from , metadata object ,total object , updated_at , and dates object and the other object date and countries give me this error

:NullReferenceException: Object reference not set to an instance of an object

I use https://json2csharp.com/ to get class from json and this is my code :

   var client = new RestClient("https://api.covid19tracking.narrativa.com/api/2020-11-05/country/us");
        client.Timeout = -1;
        var request = new RestRequest(Method.GET);
       // request.OnBeforeDeserialization = resp => { resp.ContentType = "application/json"; };
        
        Root response = client.Execute<Root>(request)?.Data;

        var paystoday_confirmed = response?.dates.date.countries.US.today_confirmed;
        if (paystoday_confirmed != null)
        {
            Debug.Log("Confirmed  :" + paystoday_confirmed);

        }

and this is my object's

   public class Link
{
    public string href { get; set; }
    public string rel { get; set; }
    public string type { get; set; }
}

public class Link2
{
    public string href { get; set; }
    public string rel { get; set; }
    public string type { get; set; }
}

public class SubRegion
{
    public string date { get; set; }
    public string id { get; set; }
    public string name { get; set; }
    public string name_es { get; set; }
    public string name_it { get; set; }
    public string source { get; set; }
    public int today_confirmed { get; set; }
    public int today_deaths { get; set; }
    public int today_new_confirmed { get; set; }
    public int today_new_deaths { get; set; }
    public int today_new_recovered { get; set; }
    public int today_recovered { get; set; }
    public double? today_vs_yesterday_confirmed { get; set; }
    public double? today_vs_yesterday_deaths { get; set; }
    public object today_vs_yesterday_recovered { get; set; }
    public int yesterday_confirmed { get; set; }
    public int yesterday_deaths { get; set; }
    public int yesterday_recovered { get; set; }
}

public class Region
{
    public string date { get; set; }
    public string id { get; set; }
    public List<Link2> links { get; set; }
    public string name { get; set; }
    public string name_es { get; set; }
    public string name_it { get; set; }
    public string source { get; set; }
    public List<SubRegion> sub_regions { get; set; }
    public int today_confirmed { get; set; }
    public int today_deaths { get; set; }
    public int today_new_confirmed { get; set; }
    public int today_new_deaths { get; set; }
    public int today_new_open_cases { get; set; }
    public int today_new_recovered { get; set; }
    public int today_new_tests { get; set; }
    public int today_new_total_hospitalised_patients { get; set; }
    public int today_open_cases { get; set; }
    public int today_recovered { get; set; }
    public int today_tests { get; set; }
    public int today_total_hospitalised_patients { get; set; }
    public double? today_vs_yesterday_confirmed { get; set; }
    public double? today_vs_yesterday_deaths { get; set; }
    public double today_vs_yesterday_open_cases { get; set; }
    public double? today_vs_yesterday_recovered { get; set; }
    public double today_vs_yesterday_tests { get; set; }
    public double? today_vs_yesterday_total_hospitalised_patients { get; set; }
    public int yesterday_confirmed { get; set; }
    public int yesterday_deaths { get; set; }
    public int yesterday_open_cases { get; set; }
    public int yesterday_recovered { get; set; }
    public int yesterday_tests { get; set; }
    public int yesterday_total_hospitalised_patients { get; set; }
}

public class US
{
    public string date { get; set; }
    public string id { get; set; }
    public List<Link> links { get; set; }
    public string name { get; set; }
    public string name_es { get; set; }
    public string name_it { get; set; }
    public List<Region> regions { get; set; }
    public string source { get; set; }
    public int today_confirmed { get; set; }
    public int today_deaths { get; set; }
    public int today_new_confirmed { get; set; }
    public int today_new_deaths { get; set; }
    public int today_new_open_cases { get; set; }
    public int today_new_recovered { get; set; }
    public int today_open_cases { get; set; }
    public int today_recovered { get; set; }
    public double today_vs_yesterday_confirmed { get; set; }
    public double today_vs_yesterday_deaths { get; set; }
    public double today_vs_yesterday_open_cases { get; set; }
    public double today_vs_yesterday_recovered { get; set; }
    public int yesterday_confirmed { get; set; }
    public int yesterday_deaths { get; set; }
    public int yesterday_open_cases { get; set; }
    public int yesterday_recovered { get; set; }
}

public class Countries
{
    public US US { get; set; }
}

public class Info
{
    public string date { get; set; }
    public string date_generation { get; set; }
    public string yesterday { get; set; }
}

public class _20201102
{
    public Countries countries { get; set; }
    public Info info { get; set; }
}

public class Dates
{
    [JsonProperty("2020-11-02")]
    public _20201102 date { get; set; }
}

public class Metadata
{
    public string by { get; set; }
    public List<string> url { get; set; }
}

public class Total
{
    public string date { get; set; }
    public string name { get; set; }
    public string name_es { get; set; }
    public string name_it { get; set; }
    public string rid { get; set; }
    public string source { get; set; }
    public int today_confirmed { get; set; }
    public int today_deaths { get; set; }
    public int today_new_confirmed { get; set; }
    public int today_new_deaths { get; set; }
    public int today_new_open_cases { get; set; }
    public int today_new_recovered { get; set; }
    public int today_open_cases { get; set; }
    public int today_recovered { get; set; }
    public double today_vs_yesterday_confirmed { get; set; }
    public double today_vs_yesterday_deaths { get; set; }
    public double today_vs_yesterday_open_cases { get; set; }
    public double today_vs_yesterday_recovered { get; set; }
    public int yesterday_confirmed { get; set; }
    public int yesterday_deaths { get; set; }
    public int yesterday_open_cases { get; set; }
    public int yesterday_recovered { get; set; }
}

public class Root
{
    public Dates dates { get; set; }
    public Metadata metadata { get; set; }
    public Total total { get; set; }
    public string updated_at { get; set; }
}

And this is the error on unity

And this is the error on unity

rivra
  • 19
  • 5
  • 1
    You have your Dates hard coded in your classes? `public class _20201102` and a reference to it `public _20201102 date { get; set; }`. This is not going to very extensible as you are going to have to create new classes and new properties for every date that you want to deserialize. – Jerry Nov 07 '20 at 08:11
  • The last code snippet you post is not objects, they are variables inside of a class, the reason why you are getting this error is because no object is being created by the class. hence, Object reference not set to an instance of an object. do you understand how classes and objects work or are you just learning unity? unless its just your English im not understanding? – Getwrong Nov 07 '20 at 08:18
  • Does this answer your question? [What is a NullReferenceException, and how do I fix it?](https://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it) – shingo Nov 07 '20 at 08:26
  • @shingo my question is why i can't got result from dates variabale ?? – rivra Nov 07 '20 at 08:43
  • @Jerry how can i create new classes and new properties for every date ??? – rivra Nov 07 '20 at 08:47
  • If you think NullReferenceException is not the matter, before we can answer your question, please show us which object is null? – shingo Nov 07 '20 at 09:18
  • Did you try to make all your classes `[System.Serializable]` and also try using fields instead of properties (remove the `{get; set;}` everywhere) Otherwise these might just be not (de)serialized and therefore be `null` – derHugo Nov 07 '20 at 09:54
  • Also note @Jerry 's comment please .. if you have different dates than hardcoding one wouldn't be quite clever ;) rather use a Dictionary here! – derHugo Nov 07 '20 at 10:08
  • @shingo var paystoday_confirmed = response?.dates.date.countries.US.today_new_confirmed; if (paystoday_confirmed != null) { Debug.Log("to day confirmed :" + paystoday_confirmed); } this give me object is null and this code : var updated_at = response?.updated_at; if (updated_at != null) { Debug.Log("date and time :" + updated_at); } and this code give me result : DATE and Time :2020-11-07 10:04UTC – rivra Nov 07 '20 at 10:18
  • The statement contains 5 returned objects, and 4 of them can throw NullReferenceException, so please take a look at [this link](https://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it) to find out the problem. – shingo Nov 07 '20 at 10:28

2 Answers2

0

As already stated in the Comments your main issue here is that you hardcoded

public class Dates
{
    [JsonProperty("2020-11-02")]
    public _20201102 date { get; set; }
}

But as you can see in your second result the date simply is not 2020-11-02 but rather 2020-10-11!

Therefore in this case there is no object in the json representing the data object => It will be the default reference value null.


So how to solve this?

You could instead use a Dictionary .. however it depends a lot on how your JSON library works. I know that at least with JSON .Net the following should work

public class Root
{
    public Dictionary<string, Date> dates { get; set; }
    public Metadata metadata { get; set; }
    public Total total { get; set; }
    public string updated_at { get; set; }
}

public class Date
{
    public Dictionary<string, Country> countries { get; set; }
    public Info info { get; set; }
}

public class Country
{
    public string date { get; set; }
    public string id { get; set; }
    public List<Link> links { get; set; }
    public string name { get; set; }
    public string name_es { get; set; }
    public string name_it { get; set; }
    public List<Region> regions { get; set; }
    public string source { get; set; }
    public int today_confirmed { get; set; }
    public int today_deaths { get; set; }
    public int today_new_confirmed { get; set; }
    public int today_new_deaths { get; set; }
    public int today_new_open_cases { get; set; }
    public int today_new_recovered { get; set; }
    public int today_open_cases { get; set; }
    public int today_recovered { get; set; }
    public double today_vs_yesterday_confirmed { get; set; }
    public double today_vs_yesterday_deaths { get; set; }
    public double today_vs_yesterday_open_cases { get; set; }
    public double today_vs_yesterday_recovered { get; set; }
    public int yesterday_confirmed { get; set; }
    public int yesterday_deaths { get; set; }
    public int yesterday_open_cases { get; set; }
    public int yesterday_recovered { get; set; }
}

This also sounds more logic since dates indicates that there might be more then one item. And also countries sounds like there might not only be US but also other countries, maybe even multiple entries.

You would then access that e.g. like

foreach(var date in response.dates)
{
    foreach(var country in date.value)
    {
        var paystoday_confirmed = country.value.today_confirmed;
        Debug.Log($"Confirmed {paystoday_confirmed} cases for the {date.key} in {country.key}");
    }
}

As complete alternative in the case you only need one certain field of your request anyway you could also use SimpleJson (simply copy the provided scripts somewhere into your project) and access them like

var root = JSON.Parse(theJsonString);
var paystoday_confirmed = root["Dates"]["2020-11-05"]["countries"]["US"]["today_confirmed"].AsInt();

For both solutions you will have to get rid of that RestClient package and rather do the UnityWebRequest.Get yourself and use the returned string instead.

derHugo
  • 83,094
  • 9
  • 75
  • 115
0

It will work best if you use dictionaries. You can make your dates and countries property a dictionary.

dates - Dates needs to be a dictionary because you can get data for different dates so the date will change

countries - The service u are using support other countries. If you change the countries to a dictionary, then the structure below should work for any country, not just for US.

Your code structure will then look something like this:


public class Root
{
    public Dictionary<string, Date> dates {get;set;}    
    public Metadata metadata { get; set; }
    public Total total { get; set; }
    public string updated_at { get; set; }
}   

public class Date
{
    public Dictionary<string, Country> countries {get;set;}
    public Info info {get;set;}
}

public class Country
{
    ....
    //Country properties here
}

public class Info
{
    ....
    //Info properties here
}   

public class Metadata
{
    ....
    //Metadata properties here
}   


public class Total
{
    ....
    //Total properties here
}   

you should then be able to process the data as follow

foreach(var kvp in root.dates)
{
    // the key will be the date eg. '2020-11-05'. 
    // This you can convert to a date using DateTime.Parse() if you need too. 
    Console.WriteLine(kvp.Key); 

    // The value will be the Date object 
    var dateObj = kvp.Value;
    var info = dateObj.info;

    foreach(var kvp2 in dateObj.countries)
    {
        Console.WriteLine(kvp2.Key);   // this will be the country eg. 'US'
        var countryDetails = kvp2.Value // this will be the Country object
    }
}

Or just change your code too:
(note: you will need to know exactly what date was returned)

var paystoday_confirmed = response?.dates["2020-11-05"].countries["US"].today_confirmed;
if (paystoday_confirmed != null)
{
    Debug.Log("Confirmed  :" + paystoday_confirmed);
}
Trekco
  • 1,246
  • 6
  • 17