6. Tutorial Lab - Alienplayer9958/Training-Module---Team-1 GitHub Wiki

Video Walkthrough

Watch the walkthrough here.

This video demonstrates how to complete the hands-on portion of the training module.

Tutorial / Lab

Part 1 — Open the Starter Project

After downloading the provided starter project, open the project in Visual Studio and build the application to make sure the starter project runs without errors.

Important: This lab does not require an Open-Meteo NuGet package. The application communicates with Open-Meteo using C#'s built-in HttpClient and reads the JSON response using System.Text.Json.

Part 2 — Create the Weather Model

The first step is to create a model that will hold the weather information returned by the Open-Meteo API.

A model is a C# class used to represent and organize data in your application. In this project, the WeatherData model will represent the information we receive from Open-Meteo, such as the latitude, longitude, temperature, humidity, and wind speed.

Step 1 — Create the Models Folder

In Solution Explorer, locate the WeatherTraining project.

  1. Right-click 'WeatherTraining'.
  2. Select Add, then click 'New Folder'.
  3. Name the folder 'Models'
  4. Right-click your 'Models' Folder
  5. Select Add, then click on 'Class'
  6. Name the class 'WeatherData.cs'

Your project should look similar to:

The following code will go into the model you just created:

using System.Text.Json.Serialization;

namespace WeatherTraining.Models;

public class WeatherData
{
    [JsonPropertyName("latitude")]
    public double Latitude { get; set; }

    [JsonPropertyName("longitude")]
    public double Longitude { get; set; }

    [JsonPropertyName("current")]
    public CurrentWeather Current { get; set; } = new();
}

public class CurrentWeather
{
    [JsonPropertyName("temperature_2m")]
    public double Temperature { get; set; }

    [JsonPropertyName("relative_humidity_2m")]
    public double Humidity { get; set; }

    [JsonPropertyName("wind_speed_10m")]
    public double WindSpeed { get; set; }
}

Here is how the code should look in Visual Studio Code:

Part 3 — Create the Weather Service

Now that we have created a model to hold our weather data, we need a way for our application to communicate with the Open-Meteo API.

We will create a weather service that is responsible for sending requests to Open-Meteo and receiving the weather information from the API.

A service is a class that handles a specific task for our application. In this project, the WeatherService will handle communication with the weather API.

Step 1 — Create the Services Folder

In Solution Explorer, locate the WeatherTraining project.

  1. Right-click 'WeatherTraining' like you did in the previous step.
  2. Select Add, then click New Folder.
  3. Name the folder 'Services'
  4. Right-Click on your Services Folder
  5. Select Add, then click 'Class'
  6. Name the class "WeatherService.cs"

Your project should look similar to:

The following code will go into the Service you just created:

using System.Net.Http;
using System.Text.Json;
using WeatherTraining.Models;

namespace WeatherTraining.Services;

public class WeatherService
{
    private readonly HttpClient _httpClient;

    public WeatherService()
    {
        _httpClient = new HttpClient();
    }
}

Here is how the code should look in Visual Studio Code:

Part 4 — Build the API Request

Now that we have created the WeatherService, we can create the request that our application will send to Open-Meteo.

An API request tells a web API what information our application wants. In this project, we will use the user's latitude and longitude to request current weather information.

Our request will ask Open-Meteo for:

Temperature

Humidity

Wind speed

We will also request the temperature in Fahrenheit and wind speed in miles per hour.

Step 1 — Create the Weather Method

Open your WeatherService.cs file.

Inside the WeatherService class, below the constructor, add the following method:

public async Task<WeatherData> GetWeatherAsync(double latitude, double longitude)
{

}

The latitude and longitude parameters allow the method to request weather for different locations.

For example, when the user selects Detroit, MI, the coordinates from the main page will be passed into this method.

Step 2 — Create the API URL

Inside the GetWeatherAsync method, create a string named url:

string url =
    $"https://api.open-meteo.com/v1/forecast" +
    $"?latitude={latitude}" +
    $"&longitude={longitude}" +
    $"&current=temperature_2m,relative_humidity_2m,wind_speed_10m" +
    $"&temperature_unit=fahrenheit" +
    $"&wind_speed_unit=mph" +
    $"&timezone=auto";

This creates the URL that will be sent to Open-Meteo.

Part 5 — Send the Request

Step 1 - Send the Request

Inside the GetWeatherAsync method, locate the API URL you created in Part 4, and driectly underneath it (Still inside the method) add the following code:

HttpResponseMessage response = await _httpClient.GetAsync(url);

The GetAsync() method sends an HTTP GET request to the URL we created.

A GET request is used when we want to retrieve information from an API.

The response from the API is stored in the response variable.

Step 2 — Check the Response

Under the request, add:

response.EnsureSuccessStatusCode();

This checks whether the API request was successful.

If Open-Meteo returns a successful HTTP status code, the program can continue.

If the request fails, EnsureSuccessStatusCode() will throw an exception. Our MainPage.xaml.cs already contains error handling that can catch this type of problem.

Step 3 — Check Your Code

Your WeatherService.cs should now look like this:

Part 6 — Read the JSON Response

Now that our application can send the API request, we need to read the response that Open-Meteo sends back.

Open-Meteo returns the weather information in JSON (JavaScript Object Notation) format. JSON is a common format used by APIs to organize and exchange data.

In this step, we will:

  1. Read the response from Open-Meteo.
  2. Store the JSON response as a string.
  3. Convert the JSON into our WeatherData model.
  4. Return the weather data to the application.

Step 1 - Read the Response

Inside the GetWeatherAsync method, locate the code you added in Part 5, and driectly underneath it (Still inside the method) add the following code:

string json = await response.Content.ReadAsStringAsync();

ReadAsStringAsync() reads the contents of the API response and stores it as a string.

For example, Open-Meteo may return JSON similar to:

{
    "latitude": 42.3314,
    "longitude": -83.0458,
    "current": {
        "temperature_2m": 68.5,
        "relative_humidity_2m": 54,
        "wind_speed_10m": 8.2
    }
}

At this point, the response is simply text stored in the json variable. We still need to convert it into something our C# application can easily work with.

Step 2 — Deserialize the JSON

Below the code you just added, enter:

 WeatherData? weather = JsonSerializer.Deserialize<WeatherData>(json);

This process is called deserialization.

Deserialization converts the JSON response into an instance of our WeatherData class.

Remember the model we created in Part 2:

[JsonPropertyName("temperature_2m")]
public double Temperature { get; set; }

The [JsonPropertyName] attribute tells the JsonSerializer which JSON property should be placed into each C# property.

Step 3 — Return the Weather Data

Finally, add the following code underneath the deserialization code:

return weather ?? throw new Exception("Unable to read weather data.");

This returns the WeatherData object to the part of the application that called GetWeatherAsync().

The ?? operator checks whether weather contains a value. If the JSON could not be converted into a WeatherData object, the application throws an exception instead.

Your finished code should look similar to:

Part 7 — Display the Weather

Our application can now send a request to Open-Meteo, receive the JSON response, and convert that response into our WeatherData model.

The final step is to take that weather information and display it on the application's interface.

We will update MainPage.xaml.cs so that the values returned from the API are placed into the labels we created in the starter project.

Step 1 — Open MainPage.xaml.cs

In Solution Explorer, open "MainPage.xaml.cs"

The starter project already contains the GetWeatherButton_Clicked method. This method runs when the user clicks the Get Weather button.

Inside this method, we already validate the latitude and longitude.

After the validation, locate the following code:

WeatherData weather =
    await _weatherService.GetWeatherAsync(latitude, longitude);

This line calls our WeatherService and waits for the weather information to be returned.

The returned data is stored in the weather variable.

Step 2 — Display the Location, Temperature, Humidity, and Wind

Directly underneath the GetWeatherAsync line, add:

LocationLabel.Text =
    $"Location: {weather.Latitude:F2}, {weather.Longitude:F2}";

TemperatureLabel.Text =
    $"{weather.Current.Temperature:F1}°F";

HumidityLabel.Text =
    $"{weather.Current.Humidity:F0}%";

WindLabel.Text =
    $"{weather.Current.WindSpeed:F1} mph";

These lines take the values from the WeatherData object and place them into the labels created in MainPage.xaml.

LocationLabel displays the latitude and longitude.

TemperatureLabel displays the current temperature.

HumidityLabel displays the current humidity.

WindLabel displays the current wind speed.

The formatting codes control how many decimal places are displayed:

F2 = 2 decimal places

F1 = 1 decimal place

F0 = no decimal places

Your code should now look something like this:

Part 8 — Add Another Weather Variable

The Open-Meteo API can provide many different types of weather information. In this activity, you will add weather code to the application.

The weather code is a numerical value provided by Open-Meteo that represents the current weather condition, such as clear skies, rain, snow, or thunderstorms.

To display a new weather variable, you need to update three parts of the application:

  1. The API request must ask for the new variable.
  2. The WeatherData model must have a property for the new value.
  3. The XAML page must have a place to display it.

This demonstrates an important concept when working with APIs: adding new data usually requires updating both the request and the code that handles the response.

Step 1 - Add Weather Code to the API Request

Open Services → WeatherService.cs.

Find the current section of the API URL:

&current=temperature_2m,relative_humidity_2m,wind_speed_10m

Add weather_code to the list:

&current=temperature_2m,relative_humidity_2m,wind_speed_10m,weather_code

Your updated URL should look like:

 string url =
     $"https://api.open-meteo.com/v1/forecast" +
     $"?latitude={latitude}" +
     $"&longitude={longitude}" +
     $"&current=temperature_2m,relative_humidity_2m,wind_speed_10m,weather_code" +
     $"&temperature_unit=fahrenheit" +
     $"&wind_speed_unit=mph" +
     $"&timezone=auto";

Step 2 — Add Weather Code to the Weather Model

Open Models → WeatherData.cs.

Inside the CurrentWeather class, add:

[JsonPropertyName("weather_code")]
public int WeatherCode { get; set; }

Your CurrentWeather class should now look like this:

Step 3 — Display the Weather Code

For this activity, you can display the numerical weather code directly.

Open MainPage.xaml.cs.

After the existing weather display code, add:

await DisplayAlert(
    "Weather Code",
    $"Current weather code: {weather.Current.WeatherCode}",
    "OK");

Your display section should now look like:

Run the application and select a location. When you click Get Weather, the weather code should appear in a popup.

Challenge — Improve the Display

Instead of displaying the numerical weather code, try changing the application so it displays a description such as:

  • Clear
  • Partly Cloudy
  • Cloudy
  • Rain
  • Snow
  • Thunderstorm

This requires creating a method that converts the numerical weather code into a readable description.

For example you can add this directly under the MainPage class:

private string GetWeatherDescription(int weatherCode)
{
    return weatherCode switch
    {
        0 => "Clear Sky",
        1 or 2 or 3 => "Cloudy",
        45 or 48 => "Fog",
        51 or 53 or 55 => "Drizzle",
        61 or 63 or 65 => "Rain",
        71 or 73 or 75 => "Snow",
        95 => "Thunderstorm",
        _ => "Unknown"
    };
}

Then, inside GetWeatherButton_Clicked, replace your current Weather Code popup:

await DisplayAlert(
    "Weather Code",
    $"Current weather code: {weather.Current.WeatherCode}",
    "OK");

with the following code:

string description =
    GetWeatherDescription(weather.Current.WeatherCode);

await DisplayAlert(
    "Current Weather",
    description,
    "OK");