C # console weather utility using .Net

What do you need to get and learn to start getting a 5-day weather forecast? 





First, decide on a weather data provider. Secondly, to analyze in what form the data is supplied and how we can collect and display it using the C # programming language. 





I chose the Accuweather service as my weather data provider. The free account currently allows 50 requests per day. This is enough to be able to view the weather data several times a day (you can even share it with a friend!). 





To register, follow the link: https://developer.accuweather.com . After registration, you need to click on the "Add a new App" button and fill out a short form. As a result, you will receive your personal ApiKey with which you can later receive updated data. 





Then the fun begins. We will analyze how and in what form the information comes and what is needed to receive weather data for a particular city. 





In the "API Reference" section, the very first list is the " Locations API " section with it and let's start. Looking ahead, I will say right away that you cannot just take and send the name of the city in a GET request. To do this, we first need to get the Location Key of a particular city. This value is presented in the form of numbers and is unique for each city. 





So, in the Locations API section, we are interested in the City Search method . We read a short description of it: Returns information for an array of cities that match the search text. Immediately take a note that an array with the names of cities is returned to us. 





In the page for the request, insert ApiKey, the name of the city of interest and put RU if we want to receive localized data. 





After clicking on the "Send this request" button below on the page, you will receive the execution result. In my case, it looks like this:





[
  {
    "Version": 1,
    "Key": "292332",
    "Type": "City",
    "Rank": 21,
    "LocalizedName": "Chelyabinsk",
    "EnglishName": "Chelyabinsk",
    "PrimaryPostalCode": "",
    "Region": {
      "ID": "ASI",
      "LocalizedName": "Asia",
      "EnglishName": "Asia"
    },
    "Country": {
      "ID": "RU",
      "LocalizedName": "Russia",
      "EnglishName": "Russia"
    },
    "AdministrativeArea": {
      "ID": "CHE",
      "LocalizedName": "Chelyabinsk",
      "EnglishName": "Chelyabinsk",
      "Level": 1,
      "LocalizedType": "Oblast",
      "EnglishType": "Oblast",
      "CountryID": "RU"
    },
    "TimeZone": {
      "Code": "YEKT",
      "Name": "Asia/Yekaterinburg",
      "GmtOffset": 5,
      "IsDaylightSaving": false,
      "NextOffsetChange": null
    },
    "GeoPosition": {
      "Latitude": 55.16,
      "Longitude": 61.403,
      "Elevation": {
        "Metric": {
          "Value": 233,
          "Unit": "m",
          "UnitType": 5
        },
        "Imperial": {
          "Value": 764,
          "Unit": "ft",
          "UnitType": 0
        }
      }
    },
    "IsAlias": false,
    "SupplementalAdminAreas": [
      {
        "Level": 2,
        "LocalizedName": "Chelyabinsk",
        "EnglishName": "Chelyabinsk"
      }
    ],
    "DataSets": [
      "AirQualityCurrentConditions",
      "AirQualityForecasts",
      "Alerts",
      "ForecastConfidence"
    ]
  }
]
      
      



As you can see, we have returned an array from one city. What will the result look like if there are two or more cities with the same name:





[
  {
    "Version": 1,
    "Key": "294021",
    "Type": "City",
    "Rank": 10,
    "LocalizedName": "",
    "EnglishName": "Moscow",
    "PrimaryPostalCode": "",
    "Region": {
      "ID": "ASI",
      "LocalizedName": "",
      "EnglishName": "Asia"
    },
    "Country": {
      "ID": "RU",
      "LocalizedName": "",
      "EnglishName": "Russia"
    },
    "AdministrativeArea": {
      "ID": "MOW",
      "LocalizedName": "",
      "EnglishName": "Moscow",
      "Level": 1,
      "LocalizedType": "  ",
      "EnglishType": "Federal City",
      "CountryID": "RU"
    },
    "TimeZone": {
      "Code": "MSK",
      "Name": "Europe/Moscow",
      "GmtOffset": 3,
      "IsDaylightSaving": false,
      "NextOffsetChange": null
    },
    "GeoPosition": {
      "Latitude": 55.752,
      "Longitude": 37.619,
      "Elevation": {
        "Metric": {
          "Value": 155,
          "Unit": "m",
          "UnitType": 5
        },
        "Imperial": {
          "Value": 508,
          "Unit": "ft",
          "UnitType": 0
        }
      }
    },
    "IsAlias": false,
    "SupplementalAdminAreas": [
      {
        "Level": 2,
        "LocalizedName": "Tsentralny",
        "EnglishName": "Tsentralny"
      }
    ],
    "DataSets": [
      "AirQualityCurrentConditions",
      "AirQualityForecasts",
      "Alerts",
      "ForecastConfidence"
    ]
  },
  {
    "Version": 1,
    "Key": "1397263",
    "Type": "City",
    "Rank": 85,
    "LocalizedName": "",
    "EnglishName": "Moskwa",
    "PrimaryPostalCode": "",
    "Region": {
      "ID": "EUR",
      "LocalizedName": "",
      "EnglishName": "Europe"
    },
    "Country": {
      "ID": "PL",
      "LocalizedName": "",
      "EnglishName": "Poland"
    },
    "AdministrativeArea": {
      "ID": "10",
      "LocalizedName": " ",
      "EnglishName": "Łódź",
      "Level": 1,
      "LocalizedType": "",
      "EnglishType": "Voivodship",
      "CountryID": "PL"
    },
    "TimeZone": {
      "Code": "CET",
      "Name": "Europe/Warsaw",
      "GmtOffset": 1,
      "IsDaylightSaving": false,
      "NextOffsetChange": "2021-03-28T01:00:00Z"
    },
    "GeoPosition": {
      "Latitude": 51.816,
      "Longitude": 19.657,
      "Elevation": {
        "Metric": {
          "Value": 238,
          "Unit": "m",
          "UnitType": 5
        },
        "Imperial": {
          "Value": 780,
          "Unit": "ft",
          "UnitType": 0
        }
      }
    },
    "IsAlias": false,
    "SupplementalAdminAreas": [
      {
        "Level": 2,
        "LocalizedName": "- ",
        "EnglishName": "Łódź East"
      },
      {
        "Level": 3,
        "LocalizedName": "",
        "EnglishName": "Nowosolna"
      }
    ],
    "DataSets": [
      "AirQualityCurrentConditions",
      "AirQualityForecasts",
      "Alerts",
      "ForecastConfidence",
      "FutureRadar",
      "MinuteCast",
      "Radar"
    ]
  },
  {
    "Version": 1,
    "Key": "580845",
    "Type": "City",
    "Rank": 85,
    "LocalizedName": "",
    "EnglishName": "Moskva",
    "PrimaryPostalCode": "",
    "Region": {
      "ID": "ASI",
      "LocalizedName": "",
      "EnglishName": "Asia"
    },
    "Country": {
      "ID": "RU",
      "LocalizedName": "",
      "EnglishName": "Russia"
    },
    "AdministrativeArea": {
      "ID": "KIR",
      "LocalizedName": "",
      "EnglishName": "Kirov",
      "Level": 1,
      "LocalizedType": "",
      "EnglishType": "Republic",
      "CountryID": "RU"
    },
    "TimeZone": {
      "Code": "MSK",
      "Name": "Europe/Moscow",
      "GmtOffset": 3,
      "IsDaylightSaving": false,
      "NextOffsetChange": null
    },
    "GeoPosition": {
      "Latitude": 57.968,
      "Longitude": 49.104,
      "Elevation": {
        "Metric": {
          "Value": 207,
          "Unit": "m",
          "UnitType": 5
        },
        "Imperial": {
          "Value": 678,
          "Unit": "ft",
          "UnitType": 0
        }
      }
    },
    "IsAlias": false,
    "SupplementalAdminAreas": [
      {
        "Level": 2,
        "LocalizedName": "Verkhoshizhemsky",
        "EnglishName": "Verkhoshizhemsky"
      }
    ],
    "DataSets": [
      "AirQualityCurrentConditions",
      "AirQualityForecasts",
      "Alerts",
      "ForecastConfidence"
    ]
  },
  {
    "Version": 1,
    "Key": "2488304",
    "Type": "City",
    "Rank": 85,
    "LocalizedName": "",
    "EnglishName": "Moskva",
    "PrimaryPostalCode": "",
    "Region": {
      "ID": "ASI",
      "LocalizedName": "",
      "EnglishName": "Asia"
    },
    "Country": {
      "ID": "RU",
      "LocalizedName": "",
      "EnglishName": "Russia"
    },
    "AdministrativeArea": {
      "ID": "PSK",
      "LocalizedName": "",
      "EnglishName": "Pskov",
      "Level": 1,
      "LocalizedType": "",
      "EnglishType": "Oblast",
      "CountryID": "RU"
    },
    "TimeZone": {
      "Code": "MSK",
      "Name": "Europe/Moscow",
      "GmtOffset": 3,
      "IsDaylightSaving": false,
      "NextOffsetChange": null
    },
    "GeoPosition": {
      "Latitude": 57.449,
      "Longitude": 29.185,
      "Elevation": {
        "Metric": {
          "Value": 161,
          "Unit": "m",
          "UnitType": 5
        },
        "Imperial": {
          "Value": 528,
          "Unit": "ft",
          "UnitType": 0
        }
      }
    },
    "IsAlias": false,
    "SupplementalAdminAreas": [
      {
        "Level": 2,
        "LocalizedName": "Porkhovsky",
        "EnglishName": "Porkhovsky"
      }
    ],
    "DataSets": [
      "AirQualityCurrentConditions",
      "AirQualityForecasts",
      "Alerts",
      "Radar"
    ]
  },
  {
    "Version": 1,
    "Key": "580847",
    "Type": "City",
    "Rank": 85,
    "LocalizedName": "",
    "EnglishName": "Moskva",
    "PrimaryPostalCode": "",
    "Region": {
      "ID": "ASI",
      "LocalizedName": "",
      "EnglishName": "Asia"
    },
    "Country": {
      "ID": "RU",
      "LocalizedName": "",
      "EnglishName": "Russia"
    },
    "AdministrativeArea": {
      "ID": "TVE",
      "LocalizedName": "",
      "EnglishName": "Tver'",
      "Level": 1,
      "LocalizedType": "",
      "EnglishType": "Oblast",
      "CountryID": "RU"
    },
    "TimeZone": {
      "Code": "MSK",
      "Name": "Europe/Moscow",
      "GmtOffset": 3,
      "IsDaylightSaving": false,
      "NextOffsetChange": null
    },
    "GeoPosition": {
      "Latitude": 56.918,
      "Longitude": 32.163,
      "Elevation": {
        "Metric": {
          "Value": 251,
          "Unit": "m",
          "UnitType": 5
        },
        "Imperial": {
          "Value": 823,
          "Unit": "ft",
          "UnitType": 0
        }
      }
    },
    "IsAlias": false,
    "SupplementalAdminAreas": [
      {
        "Level": 2,
        "LocalizedName": "Penovsky",
        "EnglishName": "Penovsky"
      }
    ],
    "DataSets": [
      "AirQualityCurrentConditions",
      "AirQualityForecasts",
      "Alerts"
    ]
  }
]
      
      



, . , Key, . .





, , . , C#. , C# VSCodium. OpenSuSe Leap 15.2.





, ApiKey, , ApiKey , ApiKey .





, UserApi:





namespace habraweatherappconsole
{
    public class UserApi
    {
        public string UserApiProperty { get;set; }
    }
}
      
      



, , :





        /// <summary>
        ///      APIKey  
        /// </summary>
        public static void ReadUserApiToLocalStorage()
        {
            XmlSerializer xmlSerializer = new XmlSerializer(typeof(ObservableCollection<UserApi>));

            try
            {
                using (StreamReader sr = new StreamReader("UserApi.xml"))
                {
                    userApiList = xmlSerializer.Deserialize(sr) as ObservableCollection<UserApi>;
                }
            }

            catch(Exception ex)
            {
                /*      .  ,     
                /     .       - -    
                /          ?
                */
            }
        }
      
      



, XML , , , XML.





. , , . , Json . , .





, :





    "Version": 1,
    "Key": "292332",
    "Type": "City",
    "Rank": 21,
    "LocalizedName": "Chelyabinsk",
    "EnglishName": "Chelyabinsk",
    "PrimaryPostalCode": "",

      
      



API , , , ( , ) , . , , - .





, :





    public class RootBasicCityInfo    {
        public int Version { get; set; } 
        public string Key { get; set; } 
        public string Type { get; set; } 
        public int Rank { get; set; } 
        public string LocalizedName { get; set; } 
        public string EnglishName { get; set; } 
        public string PrimaryPostalCode { get; set; } 

      
      



, json :





      "Region": {
        "ID": "ASI",
        "LocalizedName": "",
        "EnglishName": "Asia"
      },
      "Country": {
        "ID": "RU",
        "LocalizedName": "",
        "EnglishName": "Russia"
      },
      "AdministrativeArea": {
        "ID": "MOW",
        "LocalizedName": "",
        "EnglishName": "Moscow",
        "Level": 1,
        "LocalizedType": "  ",
        "EnglishType": "Federal City",
        "CountryID": "RU"
      },

      
      



, Region, Country, AdministrativeArea :





public class Region    {
        public string ID { get; set; } 
        public string LocalizedName { get; set; } 
        public string EnglishName { get; set; } 
    }

    public class Country    {
        public string ID { get; set; } 
        public string LocalizedName { get; set; } 
        public string EnglishName { get; set; } 
    }

    public class AdministrativeArea    {
        public string ID { get; set; } 
        public string LocalizedName { get; set; } 
        public string EnglishName { get; set; } 
        public int Level { get; set; } 
        public string LocalizedType { get; set; } 
        public string EnglishType { get; set; } 
        public string CountryID { get; set; } 
    }

      
      



:





    public class RootBasicCityInfo    {
        public int Version { get; set; } 
        public string Key { get; set; } 
        public string Type { get; set; } 
        public int Rank { get; set; } 
        public string LocalizedName { get; set; } 
        public string EnglishName { get; set; } 
        public string PrimaryPostalCode { get; set; } 
        public Region Region { get; set; } 
        public Country Country { get; set; } 
        public AdministrativeArea AdministrativeArea { get; set; } 
        public TimeZone TimeZone { get; set; } 
        public GeoPosition GeoPosition { get; set; } 
        public bool IsAlias { get; set; } 
        public List<SupplementalAdminArea> SupplementalAdminAreas { get; set; } 
        public List<string> DataSets { get; set; } 
    }

      
      



, , :





using System;
using System.Collections.ObjectModel;
using System.Net;
using System.Text.Json;

using static System.Console;

namespace habraweatherappconsole
{
    /// <summary>
    ///     
    ///       .
    /// </summary>
    public static class SearchCity
    {
        /// <summary>
        ///      .
        ///       
        ///       MainMenu.
        /// </summary>
        /// <param name="formalCityName"></param>
        public static void GettingListOfCitiesOnRequest(string formalCityName)
        {
            //  ApiKey  
            string apiKey = UserApiManager.userApiList[0].UserApiProperty;
            try
            {
                string jsonOnWeb = $"http://dataservice.accuweather.com/locations/v1/cities/search?apikey={apiKey}&q={formalCityName}";

                WebClient webClient = new WebClient();
                string prepareString = webClient.DownloadString(jsonOnWeb);

                ObservableCollection<RootBasicCityInfo> rbci = JsonSerializer.Deserialize<ObservableCollection<RootBasicCityInfo>>(prepareString);

                DataRepo.Printeceivedities(rbci);
            }
            catch (Exception ex)
            {
                WriteLine("   ."
                + " : \n" + 
                "*    \n"
                + "*    \n"
                + " : \n"
                + ex.Message);
            }

        }
    }
}
      
      



, :





        /// <summary>
        ///       
        /// (     ,  1).
        /// </summary>
        /// <param name="formalListOfCityes"></param>
        public static void Printeceivedities (ObservableCollection<RootBasicCityInfo> formalListOfCityes)
        {
            string pattern = "=====\n" + "  : {0}\n" + "  : {1}\n"
            + " :  {2} \n" + ": {3}\n" + " : {4}\n"
            + ": {5}\n" + "====\n";
            int numberInList = 0;

            foreach (var item in formalListOfCityes)
            {
                WriteLine(pattern, numberInList.ToString(),
                item.EnglishName, item.LocalizedName, item.Country.LocalizedName,
                item.AdministrativeArea.LocalizedName, item.AdministrativeArea.LocalizedType);
                numberInList++;
            }

            Write ("     : ");
            int num = Convert.ToInt32(Console.ReadLine());

            try
            {
                listOfCityForMonitorWeather.Add(formalListOfCityes[num]);
            }

            catch (Exception ex)
            {
                WriteLine(",   .\n");
                WriteLine(ex.Message);
            }
            WriteListOfCityMonitoring();
        }

      
      



, ( APIKey)





         /// <summary>
        ///       
        ///   .
        /// </summary>
        private static void WriteListOfCityMonitoring()
        {
            XmlSerializer xmlSerializer = new XmlSerializer(typeof(ObservableCollection<RootBasicCityInfo>));

            using (StreamWriter sw = new StreamWriter("RootBasicCityInfo.xml"))
            {
                xmlSerializer.Serialize(sw, listOfCityForMonitorWeather);
            }
        }

      
      



. , - 5 .





Json , , , .





Accuweather 1 , 5, 10 15 . json . Get .





, json :





  "Headline": {
    "EffectiveDate": "2021-02-23T07:00:00+03:00",
    "EffectiveEpochDate": 1614052800,
    "Severity": 3,
    "Text": "  : ",
    "Category": "cold",
    "EndDate": "2021-02-24T19:00:00+03:00",
    "EndEpochDate": 1614182400,
    "MobileLink": "http://m.accuweather.com/ru/ru/moscow/294021/extended-weather-forecast/294021?unit=c",
    "Link": "http://www.accuweather.com/ru/ru/moscow/294021/daily-weather-forecast/294021?unit=c"
  },
  "DailyForecasts": [
    {
      "Date": "2021-02-23T07:00:00+03:00",
      "EpochDate": 1614052800,
      "Temperature": {
        "Minimum": {
          "Value": -24.4,
          "Unit": "C",
          "UnitType": 17
        },
        "Maximum": {
          "Value": -20.6,
          "Unit": "C",
          "UnitType": 17
        }
      },
      "Day": {
        "Icon": 31,
        "IconPhrase": "",
        "HasPrecipitation": false
      },
      "Night": {
        "Icon": 31,
        "IconPhrase": "",
        "HasPrecipitation": false
      },
      "Sources": [
        "AccuWeather"
      ],
      "MobileLink": "http://m.accuweather.com/ru/ru/moscow/294021/daily-weather-forecast/294021?day=1&unit=c",
      "Link": "http://www.accuweather.com/ru/ru/moscow/294021/daily-weather-forecast/294021?day=1&unit=c"
    },

      
      



, :





    public class DailyForecast    {
        public DateTime Date { get; set; } 
        public int EpochDate { get; set; } 
        public Temperature Temperature { get; set; } 
        public Day Day { get; set; } 
        public Night Night { get; set; } 
        public List<string> Sources { get; set; } 
        public string MobileLink { get; set; } 
        public string Link { get; set; } 
    }
    

     public class RootWeather    {
        public Headline Headline { get; set; } 
        public List<DailyForecast> DailyForecasts { get; set; } 
    }

      
      



, ( ) . , , , :





            string pattern = "=====\n" + "  : {0}\n" + "  : {1}\n"
            + " :  {2} \n" + ": {3}\n" + " : {4}\n"
            + ": {5}\n" + "====\n";
            int numberInList = 0;

            foreach (var item in DataRepo.listOfCityForMonitorWeather)
            {
                WriteLine(pattern, numberInList.ToString(),
                item.EnglishName, item.LocalizedName, item.Country.LocalizedName,
                item.AdministrativeArea.LocalizedName, item.AdministrativeArea.LocalizedType);
                numberInList++;
            }
            
            bool ifNotExists = false;
            string cityKey = null;
            int num = 0;
            do
            {
                ifNotExists = false;
                Write("    : ");
                num = Convert.ToInt32(Console.ReadLine());
                
                if (num < 0 || num > DataRepo.listOfCityForMonitorWeather.Count - 1)
                {
                    WriteLine("  .   .");
                    ifNotExists = true;
                }
            } while(ifNotExists);
            
            cityKey = DataRepo.listOfCityForMonitorWeather[num].Key;

      
      



:





 //  ApiKey  
            string apiKey = UserApiManager.userApiList[0].UserApiProperty;
            
            string jsonUrl = $"http://dataservice.accuweather.com/forecasts/v1/daily/5day/{cityKey}?apikey={apiKey}&language=ru&metric=true";

            jsonUrl = webClient.DownloadString(jsonUrl);

            RootWeather weatherData = JsonSerializer.Deserialize<RootWeather>(jsonUrl);

            string patternWeather = "=====\n" + ": {0}\n" + " : {1}\n"
            +" : {2}\n" + "  : {3}\n" + "  : {4}\n" + "====\n";

            foreach (var item in weatherData.DailyForecasts)
            {
                WriteLine(patternWeather, item.Date, item.Temperature.Minimum.Value,
                item.Temperature.Maximum.Value, item.Day.IconPhrase, item.Night.IconPhrase);
            }
      
      



5 .





In conclusion: in this article I have shown the main points that were necessary in order for the weather data to be shown. The full source code of the utility can be found on GitLab and GitHub. Also, I will be glad to any criticism of the case and advice from senior programmers.





Thanks for your time, good luck!








All Articles