0

I am writing a C# UWP program to track weather data. When trying to access the line Debug.WriteLine("DEBUG IN WEATHERPAGE: " + myForecast.mysortedDays[1][1].desc); in the WeatherPage Class I am getting the "Object reference not set to an instance of an Object". sortedDays is a nested list which I need to be able to access fully. I know that in my GetWeather method sortedDays is populating but is null when referenced from another class. I feel it would be a case of calling a setter method but not I am unable to do this successfully with a linked list

namespace WeatherForecast
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class WeatherPage : Page
{
    Forecast myForecast;
    public WeatherPage()
    {
        this.InitializeComponent();

         myForecast = new Forecast();
        // Task task =myForecast.GetWeather("id=2964179");

        myForecast.GetWeather("id=2964179");

        Debug.WriteLine("DEBUG IN WEATHERPAGE: " + myForecast.sortedDays[1][1].desc);
    }
}
}


namespace WeatherForecast
{
class Forecast
{
    public List<List<WeatherController>> sortedDays { get; set; }
    public RootObject result { get; set; }

    public Forecast()
    {

    }
 public async void GetWeather(string cCode)
    {
        // DEBUG
        Debug.WriteLine("DEBUG: Started getWeather");
        string cityCode = cCode;
        string apiKey = "myapikey";
        // string cityCode = "id=2964179";
        string url = "myurl" + cityCode + apiKey;


        var uri = new Uri(url);
        using (HttpClient client = new HttpClient())
        {
            using (HttpResponseMessage response = await client.GetAsync(uri))
            {
                using (IHttpContent content = response.Content)
                {
                    var json = await content.ReadAsStringAsync();

                    result = JsonConvert.DeserializeObject<RootObject>(json);
                    //  SortWeather();

                    // create a list of weatherController lists to hold each day
                    // made public for global access
                    List<List<WeatherController>> sortedDays = new List<List<WeatherController>>();
                    //    sortedDays = new List<List<WeatherController>>();

                    //create a list of weatherController objects to hold each hourly interval
                    List<WeatherController> sortedHours = new List<WeatherController>();

                    // a base time
                    DateTime prevDate = Convert.ToDateTime("2000-01-01");
                    int counter = 0;

                    // iterate through result list  
                    for (int i = 0; i < result.list.Count(); i++)
                    {
                        // if the date is greater than the previous date add the sortedHours to sortedDays
                        if (Convert.ToDateTime(result.list[counter].dt_txt).Date > prevDate.Date && counter != 0)
                        {
                            sortedDays.Add(sortedHours);
                            sortedHours = new List<WeatherController>();
                        }
                        WeatherController wController = new WeatherController
                        {
                            dtime = result.list[counter].dt_txt,
                            dayOfWeek = (Convert.ToDateTime(result.list[counter].dt_txt).DayOfWeek).ToString(),
                            temp = result.list[counter].main.temp,
                            humidity = result.list[counter].main.humidity,
                            desc = result.list[counter].weather[0].description,
                            windSpeed = result.list[counter].wind.speed
                        };
                        sortedHours.Add(wController);

                        prevDate = Convert.ToDateTime(result.list[counter].dt_txt);
                        counter++;

                    }
                    // add any left over sortedHours to sortedDays
                    if (sortedHours != null)
                    {
                        sortedDays.Add(sortedHours);
                    }

                    Debug.WriteLine("DEBUG: Finished getWeather");

                }
            }
        }
    }


}
}
MidnightP
  • 105
  • 1
  • 3
  • 11
  • You have added `sortedHours` and `sortedDays` only once but acessing second one. C# collection using 0-based index. –  Mar 06 '18 at 23:49
  • break on line 1 of WeatherPage constructur and use locals window to look at myForecast.sortedDays. You will see that you have null values – pm100 Mar 06 '18 at 23:55
  • But when I debug `sortedDays` the bottom of the `GetWeather` using a nested foreach its printing as if all values are populated. – MidnightP Mar 07 '18 at 00:00
  • 1
    FYI: [You are using HttpClient wrong and it's destabilizing your software](https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/) – maccettura Mar 07 '18 at 00:24
  • interesting but didnt fix it unfortunatly – MidnightP Mar 07 '18 at 00:53

1 Answers1

1

you are assigning a local variable with the same name. see point A So basically you never assigne sortedDays property of Forecast. you must do either the code in Point B or add the line:

this.sortedDays = sortedDays;

namespace WeatherForecast
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class WeatherPage : Page
    {
        Forecast myForecast;
        public WeatherPage()
        {
            this.InitializeComponent();

            myForecast = new Forecast();
            // Task task =myForecast.GetWeather("id=2964179");
            // POINT C
            myForecast.GetWeather("id=2964179").GetAwaiter().GetResult();
            //POINT D
            Debug.WriteLine("DEBUG IN WEATHERPAGE: " + myForecast.sortedDays[1][1].desc);
        }
    }
}

namespace WeatherForecast
{
    class Forecast
    {
        public List<List<WeatherController>> sortedDays { get; set; }
        public RootObject result { get; set; }

        public Forecast()
        {

        }

        public async Task GetWeather(string cCode)
        {
            // DEBUG
            Debug.WriteLine("DEBUG: Started getWeather");
            string cityCode = cCode;
            string apiKey = "myapikey";
            // string cityCode = "id=2964179";
            string url = "myurl" + cityCode + apiKey;


            var uri = new Uri(url);
            using (HttpClient client = new HttpClient())
            {
                using (HttpResponseMessage response = await client.GetAsync(uri))
                {
                    using (IHttpContent content = response.Content)
                    {
                        var json = await content.ReadAsStringAsync();

                        result = JsonConvert.DeserializeObject<RootObject>(json);
                        //  SortWeather();

                        // create a list of weatherController lists to hold each day
                        // made public for global access
                        // POINT A
                        List<List<WeatherController>> sortedDays = new List<List<WeatherController>>(); 

                        // POINT B
                        //    sortedDays = new List<List<WeatherController>>();

                        //create a list of weatherController objects to hold each hourly interval
                        List<WeatherController> sortedHours = new List<WeatherController>();

                        // a base time
                        DateTime prevDate = Convert.ToDateTime("2000-01-01");
                        int counter = 0;

                        // iterate through result list  
                        for (int i = 0; i < result.list.Count(); i++)
                        {
                            // if the date is greater than the previous date add the sortedHours to sortedDays
                            if (Convert.ToDateTime(result.list[counter].dt_txt).Date > prevDate.Date && counter != 0)
                            {
                                sortedDays.Add(sortedHours);
                                sortedHours = new List<WeatherController>();
                            }
                            WeatherController wController = new WeatherController
                            {
                                dtime = result.list[counter].dt_txt,
                                dayOfWeek = (Convert.ToDateTime(result.list[counter].dt_txt).DayOfWeek).ToString(),
                                temp = result.list[counter].main.temp,
                                humidity = result.list[counter].main.humidity,
                                desc = result.list[counter].weather[0].description,
                                windSpeed = result.list[counter].wind.speed
                            };
                            sortedHours.Add(wController);

                            prevDate = Convert.ToDateTime(result.list[counter].dt_txt);
                            counter++;

                        }
                        // add any left over sortedHours to sortedDays
                        if (sortedHours != null)
                        {
                            sortedDays.Add(sortedHours);
                        }

                        Debug.WriteLine("DEBUG: Finished getWeather");

                    }
                }
            }
        }
    }
}

EDIT:
Also you are using an async void method so you are not awaiting the task and thus you are reaching the line in POINT D before the end of the GetWeather method. You can turn change your GetWeather method to return a Task and then use the POINT C to call it synchronously. Although i would do it in an event like Loading or Loaded and use the statement await myForecast.GetWeather("id=2964179");

Thanks,

  • I have tried both of those options already and still returning the same error. I presume you meant add `this.sortedDays = sortedDays;` to the end of the `GetWeather` method? – MidnightP Mar 07 '18 at 00:22
  • Yes I implemented your changes but no still same problem – MidnightP Mar 07 '18 at 00:26
  • @MidnightP I'm sorry i meant my latest edit. Just forgot to hit the save. – Nick Polyderopoulos Mar 07 '18 at 00:34
  • for some reason adding `.GetAwaiter().GetResult();` caused the program to halt at the line ` using (HttpResponseMessage response = await Client.GetAsync(uri))` . All locals in the debugger dissapear and go completely blank, the program still runs but doesnt pass that line – MidnightP Mar 07 '18 at 00:51
  • @MidnightP I feared that this might happen because you are on a ui thread. Could you try and hook it up on the `OnAppearing` method using async and await ? – Nick Polyderopoulos Mar 07 '18 at 00:54
  • not quite sure how to implement that,tryed and got back `WeatherPage.OnApperaring() no suitable method found to override` , never heard of `OnAppearing` so will have to look into it – MidnightP Mar 07 '18 at 01:06
  • hmmm just checked about it. I'm used to Xamarin event name. The `OnAppearing` is the same as the `Loading` ( Sorry for the confusion. I thought that xamarin.forns and uwp were sharing the same event names) – Nick Polyderopoulos Mar 07 '18 at 01:18
  • still no solution if anyone could help would be greatly appreciated – MidnightP Mar 12 '18 at 21:35