diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml
index 0c14f89..4a812de 100644
--- a/.github/workflows/dotnet.yml
+++ b/.github/workflows/dotnet.yml
@@ -20,7 +20,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
- dotnet-version: 7.0.x
+ dotnet-version: 9.0.x
- name: Restore dependencies
run: dotnet restore
diff --git a/samples/OpenWeatherMapSharp.Console/OpenWeatherMapSharp.Console.csproj b/samples/OpenWeatherMapSharp.Console/OpenWeatherMapSharp.Console.csproj
index 194867c..f035b45 100644
--- a/samples/OpenWeatherMapSharp.Console/OpenWeatherMapSharp.Console.csproj
+++ b/samples/OpenWeatherMapSharp.Console/OpenWeatherMapSharp.Console.csproj
@@ -2,13 +2,13 @@
Exe
- net7.0
+ net9.0
enable
enable
-
+
diff --git a/samples/OpenWeatherMapSharp.Console/Program.cs b/samples/OpenWeatherMapSharp.Console/Program.cs
index 4c89098..62001ac 100644
--- a/samples/OpenWeatherMapSharp.Console/Program.cs
+++ b/samples/OpenWeatherMapSharp.Console/Program.cs
@@ -3,92 +3,88 @@
using OpenWeatherMapSharp.Models.Enums;
using Spectre.Console;
+// Your OpenWeatherMap API key (replace with your actual one)
string openWeatherMapApiKey = "OWMAPIKEY";
-// HEADER
+// == HEADER ==
Grid headerGrid = new();
headerGrid.AddColumn();
headerGrid.AddRow(new FigletText("OpenWeatherMap").Centered().Color(Color.Red));
AnsiConsole.Write(headerGrid);
-// ASK FOR CITY NAME
+// == ASK FOR CITY ==
AnsiConsole.WriteLine();
string cityName = AnsiConsole.Ask("[white]Insert the name of the[/] [red]city[/][white]?[/]");
AnsiConsole.WriteLine();
-// GET WEATHER
+// == INIT SERVICE ==
OpenWeatherMapService openWeatherMapService = new(openWeatherMapApiKey);
-var geolocationResponse = await openWeatherMapService.GetLocationByNameAsync(cityName);
-if (!geolocationResponse.IsSuccess)
+// == GEOCODE ==
+OpenWeatherMapServiceResponse> geolocationResponse
+ = await openWeatherMapService.GetLocationByNameAsync(cityName);
+
+if (!geolocationResponse.IsSuccess || geolocationResponse.Response?.FirstOrDefault() is not GeocodeInfo geolocation)
{
- AnsiConsole.Write("Unfortunately I can't recognize the city. Please try again.");
- Console.WriteLine();
+ AnsiConsole.MarkupLine("[bold red]Unfortunately I can't recognize the city. Please try again.[/]");
return;
}
-var geolocations = geolocationResponse.Response;
-var geolocation = geolocations.FirstOrDefault();
+// == WEATHER ==
+OpenWeatherMapServiceResponse weatherResponse
+ = await openWeatherMapService.GetWeatherAsync(
+ geolocation.Latitude,
+ geolocation.Longitude,
+ unit: Unit.Metric);
-if (geolocation is null)
+if (!weatherResponse.IsSuccess || weatherResponse.Response is not WeatherRoot weatherRoot)
{
- AnsiConsole.Write("Unfortunately I can't recognize the city. Please try again.");
- Console.WriteLine();
+ AnsiConsole.MarkupLine("[bold red]Unfortunately I can't retrieve weather data. Please try again.[/]");
return;
}
-OpenWeatherMapServiceResponse weatherResponse = await openWeatherMapService.GetWeatherAsync(geolocation.Latitude, geolocation.Longitude, unit: Unit.Metric);
+Main mainWeather = weatherRoot.MainWeather;
-if (weatherResponse.IsSuccess)
+// == LOCATION PANEL ==
+Panel locationPanel = new(new Rows(new List
+{
+ new($"[red]City: [/]{weatherRoot.Name}"),
+ new($"[red]Latitude: [/]{weatherRoot.Coordinates.Latitude:0.0000}"),
+ new($"[red]Longitude: [/]{weatherRoot.Coordinates.Longitude:0.0000}"),
+ new($"[red]Country: [/]{geolocation.Country}"),
+ new($"[red]State: [/]{geolocation.State ?? "[not available]"}")
+}))
{
- WeatherRoot weatherRoot = weatherResponse.Response;
- Main mainWeather = weatherRoot.MainWeather;
+ Header = new PanelHeader("Location"),
+ Width = 120
+};
+AnsiConsole.Write(locationPanel);
- // LOCATION
- List locationMarkupList = new()
- {
- new Markup($"[red]City: [/]{weatherRoot.Name}"),
- new Markup($"[red]Latitude: [/]{weatherRoot.Coordinates.Latitude:0.0000}"),
- new Markup($"[red]Longitude: [/]{weatherRoot.Coordinates.Longitude:0.0000}"),
- new Markup($"[red]Country: [/]{geolocation.Country}"),
- new Markup($"[red]State: [/]{geolocation.State}")
- };
- Rows locationRows = new(locationMarkupList);
- Panel locationPanel = new(locationRows)
- {
- Header = new PanelHeader("Location"),
- Width = 120
- };
- AnsiConsole.Write(locationPanel);
+// == WEATHER PANEL ==
+List weatherMarkupList =
+[
+ new($"[red]Temperature: [/]{mainWeather.Temperature}° C"),
+ new($"[red]Feels Like: [/]{mainWeather.FeelsLikeTemperature}° C"),
+ new($"[red]Min Temperature: [/]{mainWeather.MinTemperature}° C"),
+ new($"[red]Max Temperature: [/]{mainWeather.MaxTemperature}° C"),
+ new("-----"),
+ new($"[red]Pressure (Sea Level): [/]{mainWeather.Pressure} hPa"),
+ new($"[red]Humidity: [/]{mainWeather.Humidity} %"),
+ new($"[red]Sunrise: [/]{weatherRoot.System.Sunrise:g}"),
+ new($"[red]Sunset: [/]{weatherRoot.System.Sunset:g}")
+];
- // WEATHER
- List weatherMarkupList = new()
- {
- new Markup($"[red]Temperature: [/]{mainWeather.Temperature}° C"),
- new Markup($"[red]Temperature (Feels Like): [/]{mainWeather.FeelsLikeTemperature}° C"),
- new Markup($"[red]Minimal Temperature: [/]{mainWeather.MinTemperature}° C"),
- new Markup($"[red]Maximal Temperature: [/]{mainWeather.MaxTemperature}° C"),
- new Markup("-----"),
- new Markup($"[red]Pressure Sea Level hPa: [/]{mainWeather.Pressure} hPa"),
- new Markup($"[red]Humidity: [/]{mainWeather.Humidity} %"),
- new Markup($"[red]Sunrise: [/]{weatherRoot.System.Sunrise:g}"),
- new Markup($"[red]Sunset: [/]{weatherRoot.System.Sunset:g}")
- };
- foreach (WeatherInfo weatherInfo in weatherRoot.WeatherInfos)
- {
- weatherMarkupList.Add(new Markup($"[red]Current Conditions: [/]{weatherInfo.Description}"));
- }
- Rows currentWeatherRows = new(weatherMarkupList);
- Panel currentWeatherPanel = new(currentWeatherRows)
- {
- Header = new PanelHeader("Current Weather"),
- Width = 120
- };
- AnsiConsole.Write(currentWeatherPanel);
-}
-else
+// Add weather descriptions
+foreach (WeatherInfo? weatherInfo in weatherRoot.WeatherInfos)
{
- AnsiConsole.Write("Unfortunately I can't recognize the city. Please try again.");
+ weatherMarkupList.Add(new($"[red]Conditions: [/]{weatherInfo.Description}"));
}
-Console.ReadLine();
\ No newline at end of file
+Panel weatherPanel = new(new Rows(weatherMarkupList))
+{
+ Header = new PanelHeader("Current Weather"),
+ Width = 120
+};
+AnsiConsole.Write(weatherPanel);
+
+Console.ReadLine();
diff --git a/src/OpenWeatherMapSharp/IOpenWeatherMapService.cs b/src/OpenWeatherMapSharp/IOpenWeatherMapService.cs
index efd159e..d0acf45 100644
--- a/src/OpenWeatherMapSharp/IOpenWeatherMapService.cs
+++ b/src/OpenWeatherMapSharp/IOpenWeatherMapService.cs
@@ -7,18 +7,19 @@
namespace OpenWeatherMapSharp
{
///
- /// This interface defines the methods to communicate with the Open Weather Map API
+ /// Defines the contract for communicating with the OpenWeatherMap API.
///
public interface IOpenWeatherMapService
{
///
- /// Gets forecast for a location given its longitude and latitude
+ /// Gets forecast data for a location based
+ /// on its geographic coordinates.
///
- /// The latitude of the location
- /// The longitude of the location
- /// The language used for the response
- /// The unit of measurement for the response
- /// The OpenWeatherMapServiceResponse containing the forecast information
+ /// Latitude of the location.
+ /// Longitude of the location.
+ /// Language of the response (default: English).
+ /// Unit of measurement (default: Standard).
+ /// A forecast response wrapped in .
Task> GetForecastAsync(
double latitude,
double longitude,
@@ -26,39 +27,39 @@ Task> GetForecastAsync(
Unit unit = Unit.Standard);
///
- /// Gets forecast for a location given its city ID
+ /// Gets forecast data based on a city ID.
///
- /// The ID of the location's city
- /// The language used for the response
- /// The unit of measurement for the response
- /// The OpenWeatherMapServiceResponse containing the forecast information
- [Obsolete("Please note that API requests by city name, zip-codes and city id have been deprecated. Although they are still available for use, bug fixing and updates are no longer available for this functionality.")]
+ /// The city ID.
+ /// Language of the response.
+ /// Unit of measurement.
+ /// A forecast response wrapped in .
+ [Obsolete("API requests by city name, zip-code, and city ID are deprecated and no longer maintained.")]
Task> GetForecastAsync(
int cityId,
LanguageCode language = LanguageCode.EN,
Unit unit = Unit.Standard);
///
- /// Gets forecast for a location given its city name
+ /// Gets forecast data based on a city name.
///
- /// The name of the location's city
- /// The language used for the response
- /// The unit of measurement for the response
- /// The OpenWeatherMapServiceResponse containing the forecast information
- [Obsolete("Please note that API requests by city name, zip-codes and city id have been deprecated. Although they are still available for use, bug fixing and updates are no longer available for this functionality.")]
+ /// The city name.
+ /// Language of the response.
+ /// Unit of measurement.
+ /// A forecast response wrapped in .
+ [Obsolete("API requests by city name, zip-code, and city ID are deprecated and no longer maintained.")]
Task> GetForecastAsync(
string city,
LanguageCode language = LanguageCode.EN,
Unit unit = Unit.Standard);
///
- /// Gets weather information for a location given its longitude and latitude
+ /// Gets current weather data for a location based on its geographic coordinates.
///
- /// The latitude of the location
- /// The longitude of the location
- /// The language used for the response
- /// The unit of measurement for the response
- /// The OpenWeatherMapServiceResponse containing the weather information
+ /// Latitude of the location.
+ /// Longitude of the location.
+ /// Language of the response (default: English).
+ /// Unit of measurement (default: Standard).
+ /// A weather response wrapped in .
Task> GetWeatherAsync(
double latitude,
double longitude,
@@ -66,60 +67,59 @@ Task> GetWeatherAsync(
Unit unit = Unit.Standard);
///
- /// Gets weather information for a location given its city ID
+ /// Gets current weather data based on a city ID.
///
- /// The ID of the location's city
- /// The language used for the response
- /// The unit of measurement for the response
- /// The OpenWeatherMapServiceResponse containing the weather information
- [Obsolete("Please note that API requests by city name, zip-codes and city id have been deprecated. Although they are still available for use, bug fixing and updates are no longer available for this functionality.")]
+ /// The city ID.
+ /// Language of the response.
+ /// Unit of measurement.
+ /// A weather response wrapped in .
+ [Obsolete("API requests by city name, zip-code, and city ID are deprecated and no longer maintained.")]
Task> GetWeatherAsync(
int cityId,
LanguageCode language = LanguageCode.EN,
Unit unit = Unit.Standard);
///
- /// Gets weather information for a location given its city name
+ /// Gets current weather data based on a city name.
///
- /// The name of the location's city
- /// The language used for the response
- /// The unit of measurement for the response
- /// The OpenWeatherMapServiceResponse containing the weather information
- [Obsolete("Please note that API requests by city name, zip-codes and city id have been deprecated. Although they are still available for use, bug fixing and updates are no longer available for this functionality.")]
+ /// The city name.
+ /// Language of the response.
+ /// Unit of measurement.
+ /// A weather response wrapped in .
+ [Obsolete("API requests by city name, zip-code, and city ID are deprecated and no longer maintained.")]
Task> GetWeatherAsync(
string city,
LanguageCode language = LanguageCode.EN,
Unit unit = Unit.Standard);
-
///
- /// Gets a list of locations given a query string
+ /// Gets a list of matching locations for a given query string.
///
- /// The query string to search for
- /// The maximum number of locations to return
- /// The OpenWeatherMapServiceResponse containing the list of relevant locations
+ /// The location name or part of it to search for.
+ /// The maximum number of results to return (default: 5).
+ /// A response with a list of matching objects.
Task>> GetLocationByNameAsync(
string query,
int limit = 5);
///
- /// Gets location information for a given zip code
+ /// Gets geolocation information based on a ZIP or postal code.
///
- /// The zip code to search for
- /// The OpenWeatherMapServiceResponse containing the location information
+ /// The ZIP/postal code to search for.
+ /// A response containing a object.
Task> GetLocationByZipAsync(
string zipCode);
///
- /// Gets location information for a given latitude and longitude
+ /// Gets a list of matching locations for a given pair of coordinates.
///
- /// The latitude of the location
- /// The longitude of the location
- /// The maximum number of locations to return
- /// The OpenWeatherMapServiceResponse containing the location information
+ /// Latitude of the location.
+ /// Longitude of the location.
+ /// The maximum number of results to return (default: 5).
+ /// A response with a list of objects.
Task>> GetLocationByLatLonAsync(
double latitude,
double longitude,
int limit = 5);
}
-}
\ No newline at end of file
+}
diff --git a/src/OpenWeatherMapSharp/Models/City.cs b/src/OpenWeatherMapSharp/Models/City.cs
index 2d82590..2a38e0a 100644
--- a/src/OpenWeatherMapSharp/Models/City.cs
+++ b/src/OpenWeatherMapSharp/Models/City.cs
@@ -1,66 +1,74 @@
-using Newtonsoft.Json;
-using OpenWeatherMapSharp.Utils;
+using OpenWeatherMapSharp.Utils;
using System;
+using System.Text.Json.Serialization;
namespace OpenWeatherMapSharp.Models
{
///
- /// City information
+ /// Represents basic city information,
+ /// including coordinates, country,
+ /// population, and sunrise/sunset times.
///
public class City
{
///
- /// City ID
+ /// The unique city ID as defined
+ /// by OpenWeatherMap.
///
- [JsonProperty("id")]
+ [JsonPropertyName("id")]
public int Id { get; set; }
///
- /// City name
+ /// The name of the city.
///
- [JsonProperty("name")]
+ [JsonPropertyName("name")]
public string Name { get; set; }
///
- /// Coordinates
+ /// Geographic coordinates
+ /// (latitude and longitude) of the city.
///
- [JsonProperty("coord")]
+ [JsonPropertyName("coord")]
public Coordinates Coordinates { get; set; }
///
- /// Country code (GB, JP etc.)
+ /// ISO 3166 country code (e.g., "GB", "JP").
///
- [JsonProperty("country")]
+ [JsonPropertyName("country")]
public string Country { get; set; }
///
- /// City population
+ /// Total population of the city.
///
- [JsonProperty("population")]
+ [JsonPropertyName("population")]
public int Population { get; set; }
///
- /// Sunrise time, unix, UTC
+ /// Sunrise time in Unix timestamp format (UTC).
///
- [JsonProperty("sunrise")]
+ [JsonPropertyName("sunrise")]
public long SunriseUnix { get; set; }
///
- /// Sunrise time, DateTime
+ /// Sunrise time converted to a
+ /// UTC .
///
[JsonIgnore]
- public DateTime Sunrise => SunriseUnix.ToDateTime();
+ public DateTime Sunrise
+ => SunriseUnix.ToDateTime();
///
- /// Sunset time, unix, UTC
+ /// Sunset time in Unix timestamp format (UTC).
///
- [JsonProperty("sunset")]
+ [JsonPropertyName("sunset")]
public long SunsetUnix { get; set; }
///
- /// Sunset time, DateTime
+ /// Sunset time converted to a
+ /// UTC .
///
[JsonIgnore]
- public DateTime Sunset => SunsetUnix.ToDateTime();
+ public DateTime Sunset
+ => SunsetUnix.ToDateTime();
}
}
diff --git a/src/OpenWeatherMapSharp/Models/Clouds.cs b/src/OpenWeatherMapSharp/Models/Clouds.cs
index 4333f77..b5bddf0 100644
--- a/src/OpenWeatherMapSharp/Models/Clouds.cs
+++ b/src/OpenWeatherMapSharp/Models/Clouds.cs
@@ -1,16 +1,16 @@
-using Newtonsoft.Json;
+using System.Text.Json.Serialization;
namespace OpenWeatherMapSharp.Models
{
///
- /// Clouds information
+ /// Represents cloud coverage information.
///
public class Clouds
{
///
- /// Cloudiness, %
+ /// Cloudiness percentage (0–100).
///
- [JsonProperty("all")]
+ [JsonPropertyName("all")]
public int Cloudiness { get; set; }
}
}
diff --git a/src/OpenWeatherMapSharp/Models/Coordinates.cs b/src/OpenWeatherMapSharp/Models/Coordinates.cs
index 2b3d30f..ec13883 100644
--- a/src/OpenWeatherMapSharp/Models/Coordinates.cs
+++ b/src/OpenWeatherMapSharp/Models/Coordinates.cs
@@ -1,22 +1,25 @@
-using Newtonsoft.Json;
+using System.Text.Json.Serialization;
namespace OpenWeatherMapSharp.Models
{
///
- /// Coordinates information
+ /// Represents the geographic coordinates
+ /// of a location.
///
public class Coordinates
{
///
- /// Longitude of the location
+ /// Longitude of the location,
+ /// in decimal degrees.
///
- [JsonProperty("lon")]
+ [JsonPropertyName("lon")]
public double Longitude { get; set; }
///
- /// Latitude of the location
+ /// Latitude of the location,
+ /// in decimal degrees.
///
- [JsonProperty("lat")]
+ [JsonPropertyName("lat")]
public double Latitude { get; set; }
}
}
diff --git a/src/OpenWeatherMapSharp/Models/Enums/LanguageCode.cs b/src/OpenWeatherMapSharp/Models/Enums/LanguageCode.cs
index ba4b932..fab2f9d 100644
--- a/src/OpenWeatherMapSharp/Models/Enums/LanguageCode.cs
+++ b/src/OpenWeatherMapSharp/Models/Enums/LanguageCode.cs
@@ -1,57 +1,162 @@
namespace OpenWeatherMapSharp.Models.Enums
{
///
- /// Supported languages
+ /// Represents supported language codes for API localization.
+ /// These codes align with the OpenWeatherMap API specification.
///
public enum LanguageCode
{
+ /// English
EN,
+
+ /// Afrikaans
AF,
- AL,
+
+ /// Arabic
AR,
+
+ /// Azerbaijani
AZ,
+
+ /// Belarusian
+ BE,
+
+ /// Bulgarian
BG,
+
+ /// Catalan
CA,
+
+ /// Czech (note: 'CZ' used instead of ISO 'CS')
CZ,
+
+ /// Danish
DA,
+
+ /// German
DE,
+
+ /// Greek
EL,
+
+ /// Basque
EU,
+
+ /// Persian (Farsi)
FA,
+
+ /// Finnish
FI,
+
+ /// French
FR,
+
+ /// Galician
GL,
+
+ /// Hebrew
HE,
+
+ /// Hindi
HI,
+
+ /// Croatian
HR,
+
+ /// Hungarian
HU,
+
+ /// Indonesian
ID,
+
+ /// Icelandic
+ IS,
+
+ /// Italian
IT,
+
+ /// Japanese
JA,
+
+ /// Korean
KR,
+
+ /// Kurdish
+ KU,
+
+ /// Latin
LA,
+
+ /// Lithuanian
LT,
+
+ /// Macedonian
MK,
- NO,
+
+ /// Dutch
NL,
+
+ /// Norwegian
+ NO,
+
+ /// Polish
PL,
+
+ /// Portuguese
PT,
+
+ /// Portuguese (Brazil)
PT_BR,
+
+ /// Romanian
RO,
+
+ /// Russian
RU,
- SV,
+
+ /// Northern Sami
SE,
+
+ /// Slovak
+ SK,
+
+ /// Slovenian
SL,
+
+ /// Spanish (note: 'SP' used instead of ISO 'ES')
SP,
- ES,
+
+ /// Albanian
+ SQ,
+
+ /// Serbian
SR,
+
+ /// Swedish
+ SV,
+
+ /// Thai
TH,
+
+ /// Turkish
TR,
+
+ /// Ukrainian (note: 'UA' used instead of ISO 'UK')
UA,
+
+ /// Ukrainian
UK,
+
+ /// Vietnamese
VI,
+
+ /// Chinese (Simplified)
ZH_CN,
+
+ /// Chinese (Traditional)
ZH_TW,
+
+ /// Zulu
ZU
}
}
diff --git a/src/OpenWeatherMapSharp/Models/Enums/Unit.cs b/src/OpenWeatherMapSharp/Models/Enums/Unit.cs
index d643020..e0ae237 100644
--- a/src/OpenWeatherMapSharp/Models/Enums/Unit.cs
+++ b/src/OpenWeatherMapSharp/Models/Enums/Unit.cs
@@ -1,12 +1,31 @@
namespace OpenWeatherMapSharp.Models.Enums
{
///
- /// Supported units
+ /// Represents the unit system to be used
+ /// for temperature, wind speed, and other
+ /// measurements. These options correspond
+ /// to the units supported by the
+ /// OpenWeatherMap API.
///
public enum Unit
{
+ ///
+ /// Standard units: temperature in Kelvin,
+ /// wind speed in meter/sec.
+ /// This is the default if no unit is specified.
+ ///
Standard,
+
+ ///
+ /// Imperial units: temperature in Fahrenheit,
+ /// wind speed in miles/hour.
+ ///
Imperial,
+
+ ///
+ /// Metric units: temperature in Celsius,
+ /// wind speed in meter/sec.
+ ///
Metric
}
}
diff --git a/src/OpenWeatherMapSharp/Models/ForecastItem.cs b/src/OpenWeatherMapSharp/Models/ForecastItem.cs
index 332a49e..f498a57 100644
--- a/src/OpenWeatherMapSharp/Models/ForecastItem.cs
+++ b/src/OpenWeatherMapSharp/Models/ForecastItem.cs
@@ -1,79 +1,86 @@
-using Newtonsoft.Json;
-using OpenWeatherMapSharp.Utils;
+using OpenWeatherMapSharp.Utils;
using System;
using System.Collections.Generic;
+using System.Text.Json.Serialization;
namespace OpenWeatherMapSharp.Models
{
///
- /// A Forcast Item
+ /// Represents a single forecast entry
+ /// containing weather data for a
+ /// specific point in time.
///
public class ForecastItem
{
///
- /// Main weather information
+ /// Main weather parameters such as
+ /// temperature, pressure, and humidity.
///
- [JsonProperty("main")]
+ [JsonPropertyName("main")]
public Main MainWeather { get; set; }
///
- /// List of weather infos
+ /// A list of weather conditions
+ /// (e.g., rain, clouds, clear sky).
///
- [JsonProperty("weather")]
+ [JsonPropertyName("weather")]
public List WeatherInfos { get; set; }
///
- /// Cloud information
+ /// Cloud coverage information.
///
- [JsonProperty("clouds")]
+ [JsonPropertyName("clouds")]
public Clouds Clouds { get; set; }
///
- /// Wind information
+ /// Wind speed and direction information.
///
- [JsonProperty("wind")]
+ [JsonPropertyName("wind")]
public Wind Wind { get; set; }
///
- /// Average visibility, metres
+ /// Average visibility in meters.
///
- [JsonProperty("visibility")]
+ [JsonPropertyName("visibility")]
public double Visibility { get; set; }
///
- /// Probability of precipitation
+ /// Probability of precipitation (0.0–1.0).
///
- [JsonProperty("pop")]
+ [JsonPropertyName("pop")]
public double Probability { get; set; }
///
- /// Rain information
+ /// Rain volume information.
///
- [JsonProperty("rain")]
+ [JsonPropertyName("rain")]
public Volume Rain { get; set; }
///
- /// Snow information
+ /// Snow volume information.
///
- [JsonProperty("snow")]
+ [JsonPropertyName("snow")]
public Volume Snow { get; set; }
///
- /// City information
+ /// City details associated with the forecast
+ /// (if applicable).
///
- [JsonProperty("city")]
+ [JsonPropertyName("city")]
public City City { get; set; }
///
- /// Date, Unix, UTC
+ /// Forecast time as Unix timestamp (UTC).
///
- [JsonProperty("dt")]
+ [JsonPropertyName("dt")]
public long DateUnix { get; set; }
///
- /// Date, DateTime
+ /// Forecast time as a
+ /// UTC .
///
[JsonIgnore]
- public DateTime Date => DateUnix.ToDateTime();
+ public DateTime Date
+ => DateUnix.ToDateTime();
}
}
diff --git a/src/OpenWeatherMapSharp/Models/ForecastRoot.cs b/src/OpenWeatherMapSharp/Models/ForecastRoot.cs
index 0e2705a..944a08f 100644
--- a/src/OpenWeatherMapSharp/Models/ForecastRoot.cs
+++ b/src/OpenWeatherMapSharp/Models/ForecastRoot.cs
@@ -1,41 +1,47 @@
-using Newtonsoft.Json;
-using System.Collections.Generic;
+using System.Collections.Generic;
+using System.Text.Json.Serialization;
namespace OpenWeatherMapSharp.Models
{
///
- /// The Forcast Root object
+ /// Represents the root object of a
+ /// weather forecast API response.
///
public class ForecastRoot
{
///
- /// Internal parameter
+ /// Response status code
+ /// (e.g., "200" for success).
///
- [JsonProperty("cod")]
+ [JsonPropertyName("cod")]
public string Code { get; set; }
///
- /// Internal parameter
+ /// Internal message or status value
+ /// (usage may vary by API version).
///
- [JsonProperty("message")]
+ [JsonPropertyName("message")]
public double Message { get; set; }
///
- /// A number of timestamps returned in the API response
+ /// Number of forecast entries returned
+ /// in the response.
///
- [JsonProperty("cnt")]
+ [JsonPropertyName("cnt")]
public int Count { get; set; }
///
- /// List of forecast items
+ /// List of forecast items for
+ /// different timestamps.
///
- [JsonProperty("list")]
+ [JsonPropertyName("list")]
public List Items { get; set; }
///
- /// City information
+ /// Information about the city to which
+ /// the forecast applies.
///
- [JsonProperty("city")]
+ [JsonPropertyName("city")]
public City City { get; set; }
}
}
diff --git a/src/OpenWeatherMapSharp/Models/GeocodeInfo.cs b/src/OpenWeatherMapSharp/Models/GeocodeInfo.cs
index 9645d82..6e83a46 100644
--- a/src/OpenWeatherMapSharp/Models/GeocodeInfo.cs
+++ b/src/OpenWeatherMapSharp/Models/GeocodeInfo.cs
@@ -1,44 +1,55 @@
-using Newtonsoft.Json;
-using System.Collections.Generic;
+using System.Collections.Generic;
+using System.Text.Json.Serialization;
namespace OpenWeatherMapSharp.Models
{
+ ///
+ /// Represents a geocoded location with name,
+ /// coordinates, and optional metadata such
+ /// as country and state.
+ ///
public class GeocodeInfo
{
///
- /// Name of the found location
+ /// Name of the found location.
///
- [JsonProperty("name")]
+ [JsonPropertyName("name")]
public string Name { get; set; }
///
- /// Name of the found location in dufferent languages
+ /// Localized names of the location in
+ /// different languages, keyed by
+ /// language code (e.g., "en", "de").
///
- [JsonProperty("local_names")]
+ [JsonPropertyName("local_names")]
public Dictionary LocalNames { get; set; }
///
- /// Geographical coordinates of the found location: Latitude
+ /// Latitude of the location
+ /// in decimal degrees.
///
- [JsonProperty("lat")]
+ [JsonPropertyName("lat")]
public double Latitude { get; set; }
///
- /// Geographical coordinates of the found location: Longitude
+ /// Longitude of the location
+ /// in decimal degrees.
///
- [JsonProperty("lon")]
+ [JsonPropertyName("lon")]
public double Longitude { get; set; }
///
- /// Country of the found location
+ /// Country code of the location
+ /// (ISO 3166 format, e.g., "US", "DE").
///
- [JsonProperty("country")]
+ [JsonPropertyName("country")]
public string Country { get; set; }
///
- /// State of the found location, where available
+ /// Optional state or administrative
+ /// region of the location, if available.
///
- [JsonProperty("state")]
+ [JsonPropertyName("state")]
public string State { get; set; }
}
}
diff --git a/src/OpenWeatherMapSharp/Models/GeocodeZipInfo.cs b/src/OpenWeatherMapSharp/Models/GeocodeZipInfo.cs
index 180675e..36e9d47 100644
--- a/src/OpenWeatherMapSharp/Models/GeocodeZipInfo.cs
+++ b/src/OpenWeatherMapSharp/Models/GeocodeZipInfo.cs
@@ -1,37 +1,46 @@
-using Newtonsoft.Json;
+using System.Text.Json.Serialization;
namespace OpenWeatherMapSharp.Models
{
+ ///
+ /// Represents geolocation data
+ /// returned from a ZIP/postal code
+ /// geocoding request.
+ ///
public class GeocodeZipInfo
{
///
- /// Specified zip/post code in the API request
+ /// The ZIP or postal code specified
+ /// in the API request.
///
- [JsonProperty("zip")]
+ [JsonPropertyName("zip")]
public string ZipCode { get; set; }
///
- /// Name of the found area
+ /// The name of the found area or locality.
///
- [JsonProperty("name")]
+ [JsonPropertyName("name")]
public string Name { get; set; }
///
- /// Geographical coordinates of the found location: Latitude
+ /// Latitude of the found location in
+ /// decimal degrees.
///
- [JsonProperty("lat")]
- public double Latiude { get; set; }
+ [JsonPropertyName("lat")]
+ public double Latitude { get; set; }
///
- /// Geographical coordinates of the found location: Longitude
+ /// Longitude of the found location
+ /// in decimal degrees.
///
- [JsonProperty("lon")]
+ [JsonPropertyName("lon")]
public double Longitude { get; set; }
///
- /// Country of the found zip/post code
+ /// Country code of the location
+ /// (ISO 3166 format, e.g., "US", "DE").
///
- [JsonProperty("country")]
+ [JsonPropertyName("country")]
public string Country { get; set; }
}
}
diff --git a/src/OpenWeatherMapSharp/Models/Main.cs b/src/OpenWeatherMapSharp/Models/Main.cs
index 8b66653..db85c4d 100644
--- a/src/OpenWeatherMapSharp/Models/Main.cs
+++ b/src/OpenWeatherMapSharp/Models/Main.cs
@@ -1,64 +1,76 @@
-using Newtonsoft.Json;
+using System.Text.Json.Serialization;
namespace OpenWeatherMapSharp.Models
{
///
- /// Main information
+ /// Represents the main weather data,
+ /// including temperature, pressure, and humidity.
///
public class Main
{
///
- /// Temperature.
- /// Unit Default: Kelvin, Metric: Celcius, Imperial: Fahrenheit
+ /// Current temperature.
+ /// Units — Default: Kelvin,
+ /// Metric: Celsius,
+ /// Imperial: Fahrenheit.
///
- [JsonProperty("temp")]
+ [JsonPropertyName("temp")]
public double Temperature { get; set; }
///
- /// Temperature. This temperature parameter accounts for the human perception of weather.
- /// Unit Default: Kelvin, Metric: Celcius, Imperial: Fahrenheit
+ /// Perceived temperature accounting
+ /// for human perception.
+ /// Units — Default: Kelvin,
+ /// Metric: Celsius,
+ /// Imperial: Fahrenheit.
///
- [JsonProperty("feels_like")]
+ [JsonPropertyName("feels_like")]
public double FeelsLikeTemperature { get; set; }
///
- /// Atmospheric pressure of the sea level, hPa
+ /// Atmospheric pressure at sea level, in hPa.
///
- [JsonProperty("pressure")]
+ [JsonPropertyName("pressure")]
public double Pressure { get; set; }
///
- /// Humidity, %
+ /// Humidity percentage (0–100).
///
- [JsonProperty("humidity")]
+ [JsonPropertyName("humidity")]
public double Humidity { get; set; }
///
- /// Minimum temperature at the moment.
- /// This is minimal currently observed temperature (within large megalopolises and urban areas).
- /// Unit Default: Kelvin, Metric: Celsius, Imperial: Fahrenheit
+ /// Minimum observed temperature
+ /// at the moment (typically within urban areas).
+ /// Units — Default: Kelvin,
+ /// Metric: Celsius,
+ /// Imperial: Fahrenheit.
///
- [JsonProperty("temp_min")]
+ [JsonPropertyName("temp_min")]
public double MinTemperature { get; set; }
///
- /// Maximum temperature at the moment.
- /// This is maximal currently observed temperature (within large megalopolises and urban areas).
- /// Unit Default: Kelvin, Metric: Celsius, Imperial: Fahrenheit
+ /// Maximum observed temperature
+ /// at the moment (typically within urban areas).
+ /// Units — Default: Kelvin,
+ /// Metric: Celsius,
+ /// Imperial: Fahrenheit.
///
- [JsonProperty("temp_max")]
+ [JsonPropertyName("temp_max")]
public double MaxTemperature { get; set; }
///
- /// Atmospheric pressure of the sea level, hPa
+ /// Atmospheric pressure at sea level,
+ /// in hPa.
///
- [JsonProperty("sea_level")]
+ [JsonPropertyName("sea_level")]
public double SeaLevelPressure { get; set; }
///
- /// Atmospheric pressure of the ground level, hPa
+ /// Atmospheric pressure at ground level,
+ /// in hPa.
///
- [JsonProperty("grnd_level")]
+ [JsonPropertyName("grnd_level")]
public double GroundLevelPressure { get; set; }
}
}
diff --git a/src/OpenWeatherMapSharp/Models/OpenWeatherMapServiceResponse.cs b/src/OpenWeatherMapSharp/Models/OpenWeatherMapServiceResponse.cs
index 598c62d..c364048 100644
--- a/src/OpenWeatherMapSharp/Models/OpenWeatherMapServiceResponse.cs
+++ b/src/OpenWeatherMapSharp/Models/OpenWeatherMapServiceResponse.cs
@@ -1,23 +1,32 @@
namespace OpenWeatherMapSharp.Models
{
///
- /// Wrapper for the OpenWeatherMapService response
+ /// Generic wrapper for responses returned
+ /// by the OpenWeatherMapService.
+ /// Encapsulates success status,
+ /// response data, and potential error messages.
///
- ///
- public class OpenWeatherMapServiceResponse where T : class
+ ///
+ /// The type of the response object.
+ ///
+ public class OpenWeatherMapServiceResponse
+ where T : class
{
///
- /// Indicates if the request was successful
+ /// Indicates whether the request
+ /// was successful.
///
public bool IsSuccess { get; set; }
///
- /// Contains the provided response object
+ /// The response object returned by
+ /// the service if the request was successful.
///
public T Response { get; set; }
///
- /// Error information
+ /// Error message or details
+ /// if the request failed.
///
public string Error { get; set; }
}
diff --git a/src/OpenWeatherMapSharp/Models/System.cs b/src/OpenWeatherMapSharp/Models/System.cs
index 4d445eb..c7c539a 100644
--- a/src/OpenWeatherMapSharp/Models/System.cs
+++ b/src/OpenWeatherMapSharp/Models/System.cs
@@ -1,54 +1,60 @@
-using Newtonsoft.Json;
-using OpenWeatherMapSharp.Utils;
+using OpenWeatherMapSharp.Utils;
using System;
+using System.Text.Json.Serialization;
namespace OpenWeatherMapSharp.Models
{
///
- /// System information
+ /// Contains system-related metadata
+ /// from the OpenWeatherMap API response.
///
public class System
{
///
- /// Internal parameter
+ /// Internal parameter used by the API.
///
- [JsonProperty("type")]
+ [JsonPropertyName("type")]
public int Type { get; set; }
///
- /// Internal parameter
+ /// Internal system identifier.
///
- [JsonProperty("id")]
+ [JsonPropertyName("id")]
public int Id { get; set; }
///
- /// Country code (GB, JP etc.)
+ /// Country code (ISO 3166 format),
+ /// e.g., "GB", "JP".
///
- [JsonProperty("country")]
+ [JsonPropertyName("country")]
public string Country { get; set; }
///
- /// Sunrise time, unix, UTC
+ /// Sunrise time as a Unix timestamp (UTC).
///
- [JsonProperty("sunrise")]
+ [JsonPropertyName("sunrise")]
public long SunriseUnix { get; set; }
///
- /// Sunrise time, DateTime
+ /// Sunrise time converted to a
+ /// UTC .
///
[JsonIgnore]
- public DateTime Sunrise => SunriseUnix.ToDateTime();
+ public DateTime Sunrise
+ => SunriseUnix.ToDateTime();
///
- /// Sunset time, unix, UTC
+ /// Sunset time as a Unix timestamp (UTC).
///
- [JsonProperty("sunset")]
+ [JsonPropertyName("sunset")]
public long SunsetUnix { get; set; }
///
- /// Sunset time, DateTime
+ /// Sunset time converted to a
+ /// UTC .
///
[JsonIgnore]
- public DateTime Sunset => SunsetUnix.ToDateTime();
+ public DateTime Sunset
+ => SunsetUnix.ToDateTime();
}
}
diff --git a/src/OpenWeatherMapSharp/Models/Volume.cs b/src/OpenWeatherMapSharp/Models/Volume.cs
index 4fa5291..9832972 100644
--- a/src/OpenWeatherMapSharp/Models/Volume.cs
+++ b/src/OpenWeatherMapSharp/Models/Volume.cs
@@ -1,22 +1,18 @@
-using Newtonsoft.Json;
+using System.Text.Json.Serialization;
namespace OpenWeatherMapSharp.Models
{
///
- /// Volume information
+ /// Represents precipitation volume over
+ /// a specific time period.
///
public class Volume
{
///
- /// Volume for the last 1 hour, mm.
+ /// Precipitation volume for the last
+ /// 1 hour, in millimeters.
///
- [JsonProperty("1h")]
+ [JsonPropertyName("1h")]
public double OneHour { get; set; }
-
- ///
- /// Volume for the last 3 hour, mm.
- ///
- [JsonProperty("3h")]
- public double ThreeHours { get; set; }
}
}
diff --git a/src/OpenWeatherMapSharp/Models/WeatherInfo.cs b/src/OpenWeatherMapSharp/Models/WeatherInfo.cs
index 41d6945..a45ad40 100644
--- a/src/OpenWeatherMapSharp/Models/WeatherInfo.cs
+++ b/src/OpenWeatherMapSharp/Models/WeatherInfo.cs
@@ -1,34 +1,38 @@
-using Newtonsoft.Json;
+using System.Text.Json.Serialization;
namespace OpenWeatherMapSharp.Models
{
///
- /// Weather information
+ /// Represents detailed weather condition information.
///
public class WeatherInfo
{
///
- /// Weather condition id
+ /// Weather condition ID as
+ /// defined by OpenWeatherMap.
///
- [JsonProperty("id")]
+ [JsonPropertyName("id")]
public int Id { get; set; }
///
- /// Group of weather parameters (Rain, Snow, Clouds etc.)
+ /// Broad category of weather
+ /// conditions (e.g., Rain, Snow, Clouds).
///
- [JsonProperty("main")]
+ [JsonPropertyName("main")]
public string Main { get; set; }
///
- /// Weather coniditon with the group
+ /// More detailed description of
+ /// the weather condition.
///
- [JsonProperty("description")]
+ [JsonPropertyName("description")]
public string Description { get; set; }
///
- /// Weather icon id
+ /// Weather icon ID that can be used
+ /// to retrieve the corresponding icon.
///
- [JsonProperty("icon")]
+ [JsonPropertyName("icon")]
public string Icon { get; set; }
}
}
diff --git a/src/OpenWeatherMapSharp/Models/WeatherRoot.cs b/src/OpenWeatherMapSharp/Models/WeatherRoot.cs
index d95b299..516489a 100644
--- a/src/OpenWeatherMapSharp/Models/WeatherRoot.cs
+++ b/src/OpenWeatherMapSharp/Models/WeatherRoot.cs
@@ -1,112 +1,142 @@
-using Newtonsoft.Json;
-using OpenWeatherMapSharp.Utils;
+using OpenWeatherMapSharp.Utils;
using System;
using System.Collections.Generic;
+using System.Text.Json.Serialization;
namespace OpenWeatherMapSharp.Models
{
+ ///
+ /// Represents the root object of the
+ /// current weather data response from
+ /// the OpenWeatherMap API.
+ ///
public class WeatherRoot
{
///
- /// Coordinates information
+ /// Geographic coordinates of the location.
///
- [JsonProperty("coord")]
+ [JsonPropertyName("coord")]
public Coordinates Coordinates { get; set; }
///
- /// List of weather infos
+ /// List of weather conditions.
///
- [JsonProperty("weather")]
+ [JsonPropertyName("weather")]
public List WeatherInfos { get; set; }
///
- /// Internal parameter
+ /// Internal parameter (usually "stations").
///
- [JsonProperty("base")]
+ [JsonPropertyName("base")]
public string Base { get; set; } = string.Empty;
///
- /// Main weather information
+ /// Main weather parameters such as
+ /// temperature, humidity, and pressure.
///
- [JsonProperty("main")]
+ [JsonPropertyName("main")]
public Main MainWeather { get; set; }
///
- /// Average visibility, metres
+ /// Visibility in meters.
///
- [JsonProperty("visibility")]
+ [JsonPropertyName("visibility")]
public double Visibility { get; set; } = 0;
///
- /// Wind information
+ /// Wind data including speed and direction.
///
- [JsonProperty("wind")]
+ [JsonPropertyName("wind")]
public Wind Wind { get; set; }
///
- /// Clouds information
+ /// Cloud coverage data.
///
- [JsonProperty("clouds")]
+ [JsonPropertyName("clouds")]
public Clouds Clouds { get; set; }
///
- /// Rain information
+ /// Rain volume data.
///
- [JsonProperty("rain")]
+ [JsonPropertyName("rain")]
public Volume Rain { get; set; }
///
- /// Snow information
+ /// Snow volume data.
///
- [JsonProperty("snow")]
+ [JsonPropertyName("snow")]
public Volume Snow { get; set; }
///
- /// Date, Unix, UTC
+ /// Timestamp of the weather data (Unix, UTC).
///
- [JsonProperty("dt")]
+ [JsonPropertyName("dt")]
public long DateUnix { get; set; }
///
- /// Date, DateTime
+ /// Timestamp of the weather data as a
+ /// UTC .
///
[JsonIgnore]
public DateTime Date => DateUnix.ToDateTime();
///
- /// System information
+ /// System data such as sunrise, sunset,
+ /// and country code.
///
- [JsonProperty("sys")]
+ [JsonPropertyName("sys")]
public System System { get; set; }
///
- /// City ID
+ /// Shift in seconds from UTC.
///
- [JsonProperty("id")]
+ [JsonPropertyName("timezone")]
+ public int Timezone { get; set; }
+
+ ///
+ /// City ID.
+ ///
+ [JsonPropertyName("id")]
public int CityId { get; set; }
///
- /// City name
+ /// City name.
///
- [JsonProperty("name")]
+ [JsonPropertyName("name")]
public string Name { get; set; }
///
- /// Internal parameter
+ /// Response status code.
///
- [JsonProperty("cod")]
+ [JsonPropertyName("cod")]
public int Code { get; set; }
///
- /// Icon url
+ /// Weather icon URL (default size).
+ ///
+ [JsonIgnore]
+ public string Icon
+ => $"https://openweathermap.org/img/w/{WeatherInfos?[0]?.Icon}.png";
+
+ ///
+ /// Weather icon URL (2x resolution).
+ ///
+ [JsonIgnore]
+ public string Icon2x
+ => $"https://openweathermap.org/img/w/{WeatherInfos?[0]?.Icon}@2x.png";
+
+ ///
+ /// Weather icon URL (4x resolution).
///
[JsonIgnore]
- public string Icon => $"https://openweathermap.org/img/w/{WeatherInfos?[0]?.Icon}.png";
+ public string Icon4x
+ => $"https://openweathermap.org/img/w/{WeatherInfos?[0]?.Icon}@4x.png";
///
- /// Icon name
+ /// Weather icon name.
///
[JsonIgnore]
- public string IconName => $"{WeatherInfos?[0]?.Icon}";
+ public string IconName
+ => WeatherInfos?[0]?.Icon;
}
}
diff --git a/src/OpenWeatherMapSharp/Models/Wind.cs b/src/OpenWeatherMapSharp/Models/Wind.cs
index 16a9e89..4c733ee 100644
--- a/src/OpenWeatherMapSharp/Models/Wind.cs
+++ b/src/OpenWeatherMapSharp/Models/Wind.cs
@@ -1,30 +1,34 @@
-using Newtonsoft.Json;
+using System.Text.Json.Serialization;
namespace OpenWeatherMapSharp.Models
{
///
- /// Wind information
+ /// Represents wind-related weather data,
+ /// including speed, direction, and gusts.
///
public class Wind
{
///
- /// Wind speed
- /// Unit Default: meter/sec, Metric: meter/sec, Imperial: miles/hour
+ /// Wind speed.
+ /// Units — Default & Metric:
+ /// meters/second, Imperial: miles/hour.
///
- [JsonProperty("speed")]
+ [JsonPropertyName("speed")]
public double Speed { get; set; }
///
- /// Wind direction, degrees (meteorological)
+ /// Wind direction in
+ /// meteorological degrees (0°–360°).
///
- [JsonProperty("deg")]
+ [JsonPropertyName("deg")]
public double Degrees { get; set; }
///
- /// Wind gust
- /// Unit Default: meter/sec, Metric: meter/sec, Imperial: miles/hour
+ /// Wind gust speed.
+ /// Units — Default & Metric:
+ /// meters/second, Imperial: miles/hour.
///
- [JsonProperty("gust")]
+ [JsonPropertyName("gust")]
public double Gust { get; set; }
}
}
diff --git a/src/OpenWeatherMapSharp/OpenWeatherMapService.cs b/src/OpenWeatherMapSharp/OpenWeatherMapService.cs
index 10f0264..463ba19 100644
--- a/src/OpenWeatherMapSharp/OpenWeatherMapService.cs
+++ b/src/OpenWeatherMapSharp/OpenWeatherMapService.cs
@@ -8,16 +8,17 @@
namespace OpenWeatherMapSharp
{
///
- /// This class is used to communicate with the Open Weather Map API
+ /// Provides access to the OpenWeatherMap API
+ /// for retrieving weather and geolocation data.
///
public class OpenWeatherMapService : IOpenWeatherMapService
{
private readonly string _apiKey;
///
- /// Create an instance of the OpenWeatherMapService.
+ /// Initializes a new instance of the class with the specified API key.
///
- ///
+ /// Your OpenWeatherMap API key.
public OpenWeatherMapService(string apiKey)
{
_apiKey = apiKey;
@@ -30,29 +31,48 @@ public async Task> GetWeatherAsync(
LanguageCode language = LanguageCode.EN,
Unit unit = Unit.Standard)
{
- string url = string.Format(Statics.WeatherCoordinatesUri, latitude, longitude, unit.ToString().ToLower(), language.ToString().ToLower(), _apiKey);
+ string url = string.Format(
+ Statics.WeatherCoordinatesUri,
+ latitude,
+ longitude,
+ unit.ToString("G").ToLowerInvariant(),
+ language.ToString("G").ToLowerInvariant(),
+ _apiKey);
+
return await HttpService.GetDataAsync(url);
}
///
- [Obsolete("Please note that API requests by city name, zip-codes and city id have been deprecated. Although they are still available for use, bug fixing and updates are no longer available for this functionality.")]
+ [Obsolete("API requests by city name, ZIP code, and city ID are deprecated. They are still supported, but no longer maintained or updated.")]
public async Task> GetWeatherAsync(
string city,
LanguageCode language = LanguageCode.EN,
Unit unit = Unit.Standard)
{
- string url = string.Format(Statics.WeatherCityUri, city, unit.ToString().ToLower(), language.ToString().ToLower(), _apiKey);
+ string url = string.Format(
+ Statics.WeatherCityUri,
+ city,
+ unit.ToString("G").ToLowerInvariant(),
+ language.ToString("G").ToLowerInvariant(),
+ _apiKey);
+
return await HttpService.GetDataAsync(url);
}
///
- [Obsolete("Please note that API requests by city name, zip-codes and city id have been deprecated. Although they are still available for use, bug fixing and updates are no longer available for this functionality.")]
+ [Obsolete("API requests by city name, ZIP code, and city ID are deprecated. They are still supported, but no longer maintained or updated.")]
public async Task> GetWeatherAsync(
int cityId,
LanguageCode language = LanguageCode.EN,
Unit unit = Unit.Standard)
{
- string url = string.Format(Statics.WeatherIdUri, cityId, unit.ToString().ToLower(), language.ToString().ToLower(), _apiKey);
+ string url = string.Format(
+ Statics.WeatherIdUri,
+ cityId,
+ unit.ToString("G").ToLowerInvariant(),
+ language.ToString("G").ToLowerInvariant(),
+ _apiKey);
+
return await HttpService.GetDataAsync(url);
}
@@ -63,29 +83,48 @@ public async Task> GetForecastAsync(
LanguageCode language = LanguageCode.EN,
Unit unit = Unit.Standard)
{
- string url = string.Format(Statics.ForecastCoordinatesUri, latitude, longitude, unit.ToString().ToLower(), language.ToString().ToLower(), _apiKey);
+ string url = string.Format(
+ Statics.ForecastCoordinatesUri,
+ latitude,
+ longitude,
+ unit.ToString("G").ToLowerInvariant(),
+ language.ToString("G").ToLowerInvariant(),
+ _apiKey);
+
return await HttpService.GetDataAsync(url);
}
///
- [Obsolete("Please note that API requests by city name, zip-codes and city id have been deprecated. Although they are still available for use, bug fixing and updates are no longer available for this functionality.")]
+ [Obsolete("API requests by city name, ZIP code, and city ID are deprecated. They are still supported, but no longer maintained or updated.")]
public async Task> GetForecastAsync(
string city,
LanguageCode language = LanguageCode.EN,
Unit unit = Unit.Standard)
{
- string url = string.Format(Statics.ForecastCityUri, city, unit.ToString().ToLower(), language.ToString().ToLower(), _apiKey);
+ string url = string.Format(
+ Statics.ForecastCityUri,
+ city,
+ unit.ToString("G").ToLowerInvariant(),
+ language.ToString("G").ToLowerInvariant(),
+ _apiKey);
+
return await HttpService.GetDataAsync(url);
}
///
- [Obsolete("Please note that API requests by city name, zip-codes and city id have been deprecated. Although they are still available for use, bug fixing and updates are no longer available for this functionality.")]
+ [Obsolete("API requests by city name, ZIP code, and city ID are deprecated. They are still supported, but no longer maintained or updated.")]
public async Task> GetForecastAsync(
int id,
LanguageCode language = LanguageCode.EN,
Unit unit = Unit.Standard)
{
- string url = string.Format(Statics.ForecastIdUri, id, unit.ToString().ToLower(), language.ToString().ToLower(), _apiKey);
+ string url = string.Format(
+ Statics.ForecastIdUri,
+ id,
+ unit.ToString("G").ToLowerInvariant(),
+ language.ToString("G").ToLowerInvariant(),
+ _apiKey);
+
return await HttpService.GetDataAsync(url);
}
diff --git a/src/OpenWeatherMapSharp/OpenWeatherMapSharp.csproj b/src/OpenWeatherMapSharp/OpenWeatherMapSharp.csproj
index 26e50c4..efbce50 100644
--- a/src/OpenWeatherMapSharp/OpenWeatherMapSharp.csproj
+++ b/src/OpenWeatherMapSharp/OpenWeatherMapSharp.csproj
@@ -21,13 +21,13 @@
en
-
+
-
+
-
+
diff --git a/src/OpenWeatherMapSharp/Utils/HttpService.cs b/src/OpenWeatherMapSharp/Utils/HttpService.cs
index 739d19d..cc4c797 100644
--- a/src/OpenWeatherMapSharp/Utils/HttpService.cs
+++ b/src/OpenWeatherMapSharp/Utils/HttpService.cs
@@ -1,13 +1,38 @@
-using Newtonsoft.Json;
-using OpenWeatherMapSharp.Models;
+using OpenWeatherMapSharp.Models;
using System;
using System.Net.Http;
+using System.Text.Json;
using System.Threading.Tasks;
namespace OpenWeatherMapSharp.Utils
{
+ ///
+ /// Provides internal HTTP functionality
+ /// for retrieving and deserializing
+ /// OpenWeatherMap API responses.
+ ///
internal static class HttpService
{
+ private static readonly JsonSerializerOptions defaultJsonSerializerOptions = new JsonSerializerOptions
+ {
+ PropertyNameCaseInsensitive = true
+ };
+
+ ///
+ /// Sends an HTTP GET request to the
+ /// specified URL and deserializes the
+ /// JSON response into the specified class.
+ ///
+ ///
+ /// The type to deserialize the response into.
+ ///
+ ///
+ /// The URL to send the request to.
+ ///
+ /// A task representing the asynchronous operation.
+ /// The result contains a wrapped response with
+ /// either data or an error message.
+ ///
internal static async Task> GetDataAsync(string url) where TClass : class
{
using (HttpClient client = new HttpClient())
@@ -18,13 +43,17 @@ internal static async Task> GetDataAsync
+ {
+ IsSuccess = false,
+ Error = "Empty response received from server."
+ };
}
return new OpenWeatherMapServiceResponse
{
IsSuccess = true,
- Response = JsonConvert.DeserializeObject(json)
+ Response = JsonSerializer.Deserialize(json, defaultJsonSerializerOptions)
};
}
catch (Exception ex)
diff --git a/src/OpenWeatherMapSharp/Utils/LongExtensions.cs b/src/OpenWeatherMapSharp/Utils/LongExtensions.cs
index 2f4d33c..df55bee 100644
--- a/src/OpenWeatherMapSharp/Utils/LongExtensions.cs
+++ b/src/OpenWeatherMapSharp/Utils/LongExtensions.cs
@@ -2,13 +2,27 @@
namespace OpenWeatherMapSharp.Utils
{
+ ///
+ /// Provides extension methods for
+ /// converting Unix timestamps to .
+ ///
internal static class LongExtensions
{
+ ///
+ /// Converts a Unix timestamp
+ /// (seconds since 1970-01-01 UTC)
+ /// to a local .
+ ///
+ ///
+ /// The Unix timestamp to convert.
+ ///
+ /// A object representing
+ /// the local time.
+ ///
internal static DateTime ToDateTime(this long unixTimeStamp)
{
- DateTime dateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
- dateTime = dateTime.AddSeconds(unixTimeStamp).ToLocalTime();
- return dateTime;
+ DateTime dateTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+ return dateTime.AddSeconds(unixTimeStamp).ToLocalTime();
}
}
}
diff --git a/src/OpenWeatherMapSharp/Utils/Statics.cs b/src/OpenWeatherMapSharp/Utils/Statics.cs
index bf7c671..32129ef 100644
--- a/src/OpenWeatherMapSharp/Utils/Statics.cs
+++ b/src/OpenWeatherMapSharp/Utils/Statics.cs
@@ -1,37 +1,84 @@
namespace OpenWeatherMapSharp.Utils
{
+ ///
+ /// Contains static URI templates for accessing various OpenWeatherMap API endpoints.
+ ///
internal static class Statics
{
- private static readonly string BaseUri = "https://api.openweathermap.org";
- private static readonly string WeatherBaseUri = $"{BaseUri}/data/2.5/weather";
- private static readonly string ForecastBaseUri = $"{BaseUri}/data/2.5/forecast";
- private static readonly string GeocodeBaseUri = $"{BaseUri}/geo/1.0";
+ private static readonly string BaseUri
+ = "https://api.openweathermap.org";
- public static readonly string WeatherCoordinatesUri
+ private static readonly string WeatherBaseUri
+ = $"{BaseUri}/data/2.5/weather";
+
+ private static readonly string ForecastBaseUri
+ = $"{BaseUri}/data/2.5/forecast";
+
+ private static readonly string GeocodeBaseUri
+ = $"{BaseUri}/geo/1.0";
+
+
+ ///
+ /// Weather by geographic coordinates (latitude, longitude).
+ /// Format: lat={0}&lon={1}&units={2}&lang={3}&appid={4}
+ ///
+ public static readonly string WeatherCoordinatesUri
= WeatherBaseUri + "?lat={0}&lon={1}&units={2}&lang={3}&appid={4}";
- public static readonly string WeatherCityUri
+ ///
+ /// Weather by city name.
+ /// Format: q={0}&units={1}&lang={2}&appid={3}
+ ///
+ public static readonly string WeatherCityUri
= WeatherBaseUri + "?q={0}&units={1}&lang={2}&appid={3}";
- public static readonly string WeatherIdUri
+ ///
+ /// Weather by city ID.
+ /// Format: id={0}&units={1}&lang={2}&appid={3}
+ ///
+ public static readonly string WeatherIdUri
= WeatherBaseUri + "?id={0}&units={1}&lang={2}&appid={3}";
- public static readonly string ForecastCoordinatesUri
+ ///
+ /// Forecast by geographic coordinates.
+ /// Format: lat={0}&lon={1}&units={2}&lang={3}&appid={4}
+ ///
+ public static readonly string ForecastCoordinatesUri
= ForecastBaseUri + "?lat={0}&lon={1}&units={2}&lang={3}&appid={4}";
-
- public static readonly string ForecastCityUri
+
+ ///
+ /// Forecast by city name.
+ /// Format: q={0}&units={1}&lang={2}&appid={3}
+ ///
+ public static readonly string ForecastCityUri
= ForecastBaseUri + "?q={0}&units={1}&lang={2}&appid={3}";
- public static readonly string ForecastIdUri
+ ///
+ /// Forecast by city ID.
+ /// Format: id={0}&units={1}&lang={2}&appid={3}
+ ///
+ public static readonly string ForecastIdUri
= ForecastBaseUri + "?id={0}&units={1}&lang={2}&appid={3}";
- public static readonly string GeocodeLocationUri
+ ///
+ /// Geocoding by location name.
+ /// Format: q={0}&limit={1}&appid={2}
+ ///
+ public static readonly string GeocodeLocationUri
= GeocodeBaseUri + "/direct?q={0}&limit={1}&appid={2}";
- public static readonly string GeocodeZipUri
+ ///
+ /// Geocoding by ZIP/postal code.
+ /// Format: zip={0}&appid={1}
+ ///
+ public static readonly string GeocodeZipUri
= GeocodeBaseUri + "/zip?zip={0}&appid={1}";
- public static readonly string GeocodeReverseUri
+ ///
+ /// Reverse geocoding by geographic coordinates.
+ /// Format: lat={0}&lon={1}&limit={2}&appid={3}
+ ///
+ public static readonly string GeocodeReverseUri
= GeocodeBaseUri + "/reverse?lat={0}&lon={1}&limit={2}&appid={3}";
}
}
diff --git a/tests/OpenWeatherMapSharp.UnitTests/GlobalUsings.cs b/tests/OpenWeatherMapSharp.UnitTests/GlobalUsings.cs
deleted file mode 100644
index 8c927eb..0000000
--- a/tests/OpenWeatherMapSharp.UnitTests/GlobalUsings.cs
+++ /dev/null
@@ -1 +0,0 @@
-global using Xunit;
\ No newline at end of file
diff --git a/tests/OpenWeatherMapSharp.UnitTests/OpenWeatherMapServiceTests.cs b/tests/OpenWeatherMapSharp.UnitTests/OpenWeatherMapServiceTests.cs
index 42c8802..a751675 100644
--- a/tests/OpenWeatherMapSharp.UnitTests/OpenWeatherMapServiceTests.cs
+++ b/tests/OpenWeatherMapSharp.UnitTests/OpenWeatherMapServiceTests.cs
@@ -1,212 +1,268 @@
using OpenWeatherMapSharp.Models;
+using OpenWeatherMapSharp.Models.Enums;
+using Xunit;
namespace OpenWeatherMapSharp.UnitTests;
+///
+/// Integration tests for the OpenWeatherMapService using actual API requests.
+///
public class OpenWeatherMapServiceTests
{
private const string OPENWEATHERMAPAPIKEY = "OWMAPIKEY";
-
[Fact]
public async Task BasicInvalidCredentials()
{
- // arrange
- OpenWeatherMapService service = new("apikey");
+ // Arrange
+ OpenWeatherMapService service = new("invalid_api_key");
string cityName = "Pforzheim";
- // act
- OpenWeatherMapServiceResponse serviceResponse = await service.GetWeatherAsync(cityName);
+ // Act
+ OpenWeatherMapServiceResponse serviceResponse
+ = await service.GetWeatherAsync(cityName);
- // assert
+ // Assert
Assert.NotNull(serviceResponse);
Assert.False(serviceResponse.IsSuccess);
Assert.NotNull(serviceResponse.Error);
}
-
[Fact]
- public async Task GetWeatherLocationTest()
+ public async Task GetWeatherByCoordinates_ShouldReturnCorrectLocation()
{
- // arrange
+ // Arrange
OpenWeatherMapService service = new(OPENWEATHERMAPAPIKEY);
double latitude = 48.89;
double longitude = 8.69;
- // act
- OpenWeatherMapServiceResponse serviceResponse = await service.GetWeatherAsync(latitude, longitude);
+ // Act
+ OpenWeatherMapServiceResponse serviceResponse
+ = await service.GetWeatherAsync(latitude, longitude);
- // assert
+ // Assert
Assert.NotNull(serviceResponse);
Assert.NotNull(serviceResponse.Response);
Assert.Null(serviceResponse.Error);
Assert.True(serviceResponse.IsSuccess);
- Assert.Equal(serviceResponse.Response.Coordinates.Latitude, latitude);
- Assert.Equal(serviceResponse.Response.Coordinates.Longitude, longitude);
+ Assert.Equal(latitude, serviceResponse.Response.Coordinates.Latitude);
+ Assert.Equal(longitude, serviceResponse.Response.Coordinates.Longitude);
}
[Fact]
- public async Task GetWeatherCityNameTest()
+ public async Task GetWeatherByCityName_ShouldReturnCorrectCity()
{
- // arrange
+ // Arrange
OpenWeatherMapService service = new(OPENWEATHERMAPAPIKEY);
string cityName = "Pforzheim";
- // act
- OpenWeatherMapServiceResponse serviceResponse = await service.GetWeatherAsync(cityName);
+ // Act
+ OpenWeatherMapServiceResponse serviceResponse
+ = await service.GetWeatherAsync(cityName);
- // assert
+ // Assert
Assert.NotNull(serviceResponse);
Assert.NotNull(serviceResponse.Response);
Assert.Null(serviceResponse.Error);
Assert.True(serviceResponse.IsSuccess);
- Assert.Equal(serviceResponse.Response.Name, cityName);
+ Assert.Equal(cityName, serviceResponse.Response.Name);
}
[Fact]
- public async Task GetWeatherCityIdTest()
+ public async Task GetWeatherByCityId_ShouldReturnCorrectCity()
{
- // arrange
+ // Arrange
OpenWeatherMapService service = new(OPENWEATHERMAPAPIKEY);
int cityId = 2928810;
string cityName = "Essen";
- // act
- OpenWeatherMapServiceResponse serviceResponse = await service.GetWeatherAsync(cityId);
+ // Act
+ OpenWeatherMapServiceResponse serviceResponse
+ = await service.GetWeatherAsync(cityId);
- // assert
+ // Assert
Assert.NotNull(serviceResponse);
Assert.NotNull(serviceResponse.Response);
Assert.Null(serviceResponse.Error);
Assert.True(serviceResponse.IsSuccess);
- Assert.Equal(serviceResponse.Response.Name, cityName);
+ Assert.Equal(cityName, serviceResponse.Response.Name);
}
-
[Fact]
- public async Task GetForecastLocationTest()
+ public async Task GetForecastByCoordinates_ShouldReturnCorrectLocation()
{
- // arrange
+ // Arrange
OpenWeatherMapService service = new(OPENWEATHERMAPAPIKEY);
double latitude = 48.89;
double longitude = 8.69;
- // act
- OpenWeatherMapServiceResponse serviceResponse = await service.GetForecastAsync(latitude, longitude);
+ // Act
+ OpenWeatherMapServiceResponse serviceResponse
+ = await service.GetForecastAsync(latitude, longitude);
- // assert
+ // Assert
Assert.NotNull(serviceResponse);
Assert.NotNull(serviceResponse.Response);
Assert.Null(serviceResponse.Error);
Assert.True(serviceResponse.IsSuccess);
- Assert.Equal(serviceResponse.Response.City.Coordinates.Latitude, latitude);
- Assert.Equal(serviceResponse.Response.City.Coordinates.Longitude, longitude);
+ Assert.Equal(latitude, serviceResponse.Response.City.Coordinates.Latitude);
+ Assert.Equal(longitude, serviceResponse.Response.City.Coordinates.Longitude);
}
[Fact]
- public async Task GetForecastCityNameTest()
+ public async Task GetForecastByCityName_ShouldReturnCorrectCity()
{
- // arrange
+ // Arrange
OpenWeatherMapService service = new(OPENWEATHERMAPAPIKEY);
string cityName = "Pforzheim";
- // act
- OpenWeatherMapServiceResponse serviceResponse = await service.GetForecastAsync(cityName);
+ // Act
+ OpenWeatherMapServiceResponse serviceResponse
+ = await service.GetForecastAsync(cityName);
- // assert
+ // Assert
Assert.NotNull(serviceResponse);
Assert.NotNull(serviceResponse.Response);
Assert.Null(serviceResponse.Error);
Assert.True(serviceResponse.IsSuccess);
- Assert.Equal(serviceResponse.Response.City.Name, cityName);
+ Assert.Equal(cityName, serviceResponse.Response.City.Name);
}
[Fact]
- public async Task GetForecastCityIdTest()
+ public async Task GetForecastByCityId_ShouldReturnCorrectCity()
{
- // arrange
+ // Arrange
OpenWeatherMapService service = new(OPENWEATHERMAPAPIKEY);
int cityId = 2928810;
string cityName = "Essen";
- // act
- OpenWeatherMapServiceResponse serviceResponse = await service.GetForecastAsync(cityId);
+ // Act
+ OpenWeatherMapServiceResponse serviceResponse
+ = await service.GetForecastAsync(cityId);
- // assert
+ // Assert
Assert.NotNull(serviceResponse);
Assert.NotNull(serviceResponse.Response);
Assert.Null(serviceResponse.Error);
Assert.True(serviceResponse.IsSuccess);
- Assert.Equal(serviceResponse.Response.City.Name, cityName);
+ Assert.Equal(cityName, serviceResponse.Response.City.Name);
}
-
[Fact]
- public async Task GetGeolocationFromNameTest()
+ public async Task GetGeolocationByName_ShouldReturnCorrectLocation()
{
- // arrange
+ // Arrange
OpenWeatherMapService service = new(OPENWEATHERMAPAPIKEY);
string name = "Pforzheim";
string country = "DE";
- // act
- OpenWeatherMapServiceResponse> serviceResponse = await service.GetLocationByNameAsync(name);
+ // Act
+ OpenWeatherMapServiceResponse> serviceResponse
+ = await service.GetLocationByNameAsync(name);
- // assert
+ // Assert
Assert.NotNull(serviceResponse);
Assert.NotNull(serviceResponse.Response);
Assert.Null(serviceResponse.Error);
Assert.True(serviceResponse.IsSuccess);
- GeocodeInfo? firstCountry = serviceResponse.Response.FirstOrDefault();
- Assert.NotNull(firstCountry);
- Assert.Equal(name, firstCountry.Name);
- Assert.Equal(country, firstCountry.Country);
+ GeocodeInfo? firstResult = serviceResponse.Response.FirstOrDefault();
+ Assert.NotNull(firstResult);
+ Assert.Equal(name, firstResult.Name);
+ Assert.Equal(country, firstResult.Country);
}
[Fact]
- public async Task GetGeolocationFromZipTest()
+ public async Task GetGeolocationByCoordinates_ShouldReturnCorrectLocation()
{
- // arrange
+ // Arrange
OpenWeatherMapService service = new(OPENWEATHERMAPAPIKEY);
- string zipCode = "75173";
+ double latitude = 48.89;
+ double longitude = 8.69;
string cityName = "Pforzheim";
string country = "DE";
- // act
- OpenWeatherMapServiceResponse serviceResponse = await service.GetLocationByZipAsync($"{zipCode},{country}");
+ // Act
+ OpenWeatherMapServiceResponse> serviceResponse
+ = await service.GetLocationByLatLonAsync(latitude, longitude);
- // assert
+ // Assert
Assert.NotNull(serviceResponse);
Assert.NotNull(serviceResponse.Response);
Assert.Null(serviceResponse.Error);
Assert.True(serviceResponse.IsSuccess);
- Assert.Equal(zipCode, serviceResponse.Response.ZipCode);
- Assert.Equal(cityName, serviceResponse.Response.Name);
- Assert.Equal(country, serviceResponse.Response.Country);
+
+ GeocodeInfo? firstResult = serviceResponse.Response.FirstOrDefault();
+ Assert.NotNull(firstResult);
+ Assert.Equal(cityName, firstResult.Name);
+ Assert.Equal(country, firstResult.Country);
}
[Fact]
- public async Task GetGeolocationFromLatLonTest()
+ public void Constructor_WithEmptyApiKey_ShouldNotThrowButLikelyFailAtRuntime()
{
- // arrange
+ // Arrange
+ OpenWeatherMapService service = new("");
+
+ // Act
+
+ // Assert
+ Assert.NotNull(service);
+ }
+
+ [Theory]
+ [InlineData(LanguageCode.EN, Unit.Standard)]
+ [InlineData(LanguageCode.DE, Unit.Metric)]
+ [InlineData(LanguageCode.FR, Unit.Imperial)]
+ public async Task GetWeather_WithDifferentLanguagesAndUnits_ShouldSucceed(LanguageCode lang, Unit unit)
+ {
+ // Arrange
OpenWeatherMapService service = new(OPENWEATHERMAPAPIKEY);
- double latitude = 48.89;
- double longitude = 8.69;
- string cityName = "Pforzheim";
- string country = "DE";
- // act
- OpenWeatherMapServiceResponse> serviceResponse = await service.GetLocationByLatLonAsync(latitude, longitude);
+ // Act
+ OpenWeatherMapServiceResponse response
+ = await service.GetWeatherAsync(48.89, 8.69, lang, unit);
- // assert
- Assert.NotNull(serviceResponse);
- Assert.NotNull(serviceResponse.Response);
- Assert.Null(serviceResponse.Error);
- Assert.True(serviceResponse.IsSuccess);
+ // Assert
+ Assert.NotNull(response);
+ Assert.True(response.IsSuccess);
+ Assert.NotNull(response.Response);
+ Assert.Null(response.Error);
+ }
+
+ [Fact]
+ public async Task GetGeolocation_WithInvalidCity_ShouldReturnEmptyResult()
+ {
+ // Arrange
+ OpenWeatherMapService service = new(OPENWEATHERMAPAPIKEY);
+
+ // Act
+ OpenWeatherMapServiceResponse> response
+ = await service.GetLocationByNameAsync("NowherevilleXYZ");
+
+ // Assert
+ Assert.NotNull(response);
+ Assert.True(response.IsSuccess);
+ Assert.NotNull(response.Response);
+ Assert.Empty(response.Response);
+ }
+
+ [Theory]
+ [InlineData(-999, 10)]
+ [InlineData(91, 10)]
+ [InlineData(10, -200)]
+ public async Task GetWeather_WithInvalidCoordinates_ShouldFail(double lat, double lon)
+ {
+ // Arrange
+ OpenWeatherMapService service = new(OPENWEATHERMAPAPIKEY);
+
+ // Act
+ OpenWeatherMapServiceResponse response
+ = await service.GetWeatherAsync(lat, lon);
- GeocodeInfo? firstCountry = serviceResponse.Response.FirstOrDefault();
- Assert.NotNull(firstCountry);
- Assert.Equal(cityName, firstCountry.Name);
- Assert.Equal(country, firstCountry.Country);
+ // Assert
+ Assert.NotNull(response);
+ Assert.False(response.IsSuccess);
+ Assert.NotNull(response.Error);
}
}
\ No newline at end of file
diff --git a/tests/OpenWeatherMapSharp.UnitTests/OpenWeatherMapSharp.UnitTests.csproj b/tests/OpenWeatherMapSharp.UnitTests/OpenWeatherMapSharp.UnitTests.csproj
index 200077d..2dfe0b0 100644
--- a/tests/OpenWeatherMapSharp.UnitTests/OpenWeatherMapSharp.UnitTests.csproj
+++ b/tests/OpenWeatherMapSharp.UnitTests/OpenWeatherMapSharp.UnitTests.csproj
@@ -1,7 +1,7 @@
-
+
- net7.0
+ net9.0
enable
enable
@@ -10,13 +10,13 @@
-
-
-
+
+
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all