Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dotnet 8 #34

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ on:
paths:
- '**/*.cs'
- '**/*.csproj'
workflow_dispatch:

env:
DOTNET_VERSION: '6.x.x' # The .NET SDK version to use
DOTNET_VERSION: '8.x.x' # The .NET SDK version to use

jobs:
build-and-test:
Expand All @@ -22,7 +23,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macOS-latest]
os: [ubuntu-latest]

steps:
- name: Checkout Code
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/package-and-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,5 @@ jobs:
- name: Package nuget
run: dotnet pack ./OpenMeteo/OpenMeteo.csproj --configuration release -o:package /p:PackageVersion=${{ steps.gitversion.outputs.AssemblySemVer }}

- name: Push generated package to NuGet.org
run: dotnet nuget push ./package/*.nupkg --api-key ${{ secrets.API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
- name: Push generated package to Github Packages
run: dotnet nuget push ./package/*.nupkg --api-key ${{ secrets.GITHUB_TOKEN }} --source https://nuget.pkg.github.com/colinnuk/index.json --skip-duplicate
49 changes: 0 additions & 49 deletions .github/workflows/test-dev-build.yml

This file was deleted.

12 changes: 12 additions & 0 deletions OpenMeteo/ElevationApiResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace OpenMeteo
{
/// <summary>
/// Elevation API response
/// </summary>
public class ElevationApiResponse
{
/// <summary>
/// Elevation array in meters - this library currently only supports 1 input elevation so this will always be a single value array
public float[]? Elevation { get; set; }
}
}
21 changes: 21 additions & 0 deletions OpenMeteo/ElevationOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
namespace OpenMeteo
{
internal class ElevationOptions
{
public ElevationOptions(float latitude, float longitude)
{
Latitude = latitude;
Longitude = longitude;
}

/// <summary>
/// Geographical WGS84 coordinate of the location
/// </summary>
public float Latitude { get; set; }

/// <summary>
/// Geographical WGS84 coordinate of the location
/// </summary>
public float Longitude { get; set; }
}
}
13 changes: 13 additions & 0 deletions OpenMeteo/ErrorResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System.Text.Json.Serialization;

namespace OpenMeteo
{
internal class ErrorResponse
{
[JsonPropertyName("reason")]
public string? Reason { get; set; }

[JsonPropertyName("error")]
public bool Error { get; set; }
}
}
9 changes: 6 additions & 3 deletions OpenMeteo/HttpController.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Http;

namespace OpenMeteo
Expand All @@ -15,7 +13,12 @@ internal class HttpController

public HttpController()
{
_httpClient = new HttpClient();
var socketHttpHandler = new SocketsHttpHandler()
{
PooledConnectionLifetime = TimeSpan.FromMinutes(4),
};
_httpClient = new HttpClient(socketHttpHandler);

_httpClient.DefaultRequestHeaders.Accept.Clear();
_httpClient.DefaultRequestHeaders.Accept.Add(
new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json")
Expand Down
16 changes: 16 additions & 0 deletions OpenMeteo/IOpenMeteoLogger.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace OpenMeteo
{
/// <summary>
/// Specifies a simple interface for a logger.
/// Usage of this interface is optional.
/// To use this, create your own implementation of this interface which you can easily setup
/// to call your own logging framework.
/// </summary>
public interface IOpenMeteoLogger
{
void Information(string message);
void Warning(string message);
void Error(string message);
void Debug(string message);
}
}
8 changes: 4 additions & 4 deletions OpenMeteo/OpenMeteo.csproj
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<PackageId>$(AssemblyName).dotnet</PackageId>
<Title>Open Meteo Dotnet Library</Title>
<PackageId>$(AssemblyName).colinnuk.dotnet</PackageId>
<Title>Open Meteo Dotnet 8 Library</Title>
<Version>0.0.3</Version>
<Authors>AlienDwarf</Authors>
<Company />
Expand All @@ -17,7 +17,7 @@
<AssemblyVersion>0.0.1</AssemblyVersion>
<FileVersion>0.0.1</FileVersion>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<Description>A .Net Standard 2.1 library for the Open-Meteo.com API.</Description>
<Description>A DotNet 8 library for the Open-Meteo.com API.</Description>
<IncludeSymbols>True</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<SignAssembly>False</SignAssembly>
Expand Down
128 changes: 107 additions & 21 deletions OpenMeteo/OpenMeteoClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,12 @@ public class OpenMeteoClient
private readonly string _weatherApiUrl = "https://api.open-meteo.com/v1/forecast";
private readonly string _geocodeApiUrl = "https://geocoding-api.open-meteo.com/v1/search";
private readonly string _airQualityApiUrl = "https://air-quality-api.open-meteo.com/v1/air-quality";
private readonly string _elevationApiUrl = "https://api.open-meteo.com/v1/elevation";
private readonly HttpController httpController;

private readonly IOpenMeteoLogger? _logger = default!;
private readonly bool _rethrowExceptions = false;

/// <summary>
/// Creates a new <seealso cref="OpenMeteoClient"/> object and sets the neccessary variables (httpController, CultureInfo)
/// </summary>
Expand All @@ -24,6 +28,16 @@ public OpenMeteoClient()
httpController = new HttpController();
}

/// <summary>
/// Creates a new <seealso cref="OpenMeteoClient"/> object and sets the neccessary variables (httpController, CultureInfo)
/// </summary>
public OpenMeteoClient(bool rethrowExceptions, IOpenMeteoLogger? logger = null)
{
httpController = new HttpController();
_logger = logger;
_rethrowExceptions = rethrowExceptions;
}

/// <summary>
/// Performs two GET-Requests (first geocoding api for latitude,longitude, then weather forecast)
/// </summary>
Expand Down Expand Up @@ -79,14 +93,7 @@ public OpenMeteoClient()
/// <returns>Awaitable Task containing WeatherForecast or NULL</returns>
public async Task<WeatherForecast?> QueryAsync(WeatherForecastOptions options)
{
try
{
return await GetWeatherForecastAsync(options);
}
catch (Exception)
{
return null;
}
return await GetWeatherForecastAsync(options);
}

/// <summary>
Expand Down Expand Up @@ -164,6 +171,19 @@ public OpenMeteoClient()
return (response.Locations[0].Latitude, response.Locations[0].Longitude);
}

/// <summary>
/// Performs one GET-Request to Open-Meteo Elevation API
/// </summary>
/// <param name="latitude">Latitude</param>
/// <param name="longitude">Longitude</param>
/// <returns></returns>
public async Task<ElevationApiResponse?> QueryElevationAsync(float latitude, float longitude)
{
ElevationOptions elevationOptions = new ElevationOptions(latitude, longitude);

return await GetElevationAsync(elevationOptions);
}

public WeatherForecast? Query(WeatherForecastOptions options)
{
return QueryAsync(options).GetAwaiter().GetResult();
Expand Down Expand Up @@ -194,20 +214,28 @@ public OpenMeteoClient()
return QueryAsync(options).GetAwaiter().GetResult();
}

public ElevationApiResponse? QueryElevation(float latitude, float longitude)
{
return QueryElevationAsync(latitude, longitude).GetAwaiter().GetResult();
}

private async Task<AirQuality?> GetAirQualityAsync(AirQualityOptions options)
{
try
{
HttpResponseMessage response = await httpController.Client.GetAsync(MergeUrlWithOptions(_airQualityApiUrl, options));
var url = MergeUrlWithOptions(_airQualityApiUrl, options);
_logger?.Debug($"{nameof(OpenMeteoClient)}.GetAirQualityAsync(). URL: {url}");
HttpResponseMessage response = await httpController.Client.GetAsync(url);
response.EnsureSuccessStatusCode();

AirQuality? airQuality = await JsonSerializer.DeserializeAsync<AirQuality>(await response.Content.ReadAsStreamAsync(), new JsonSerializerOptions() { PropertyNameCaseInsensitive = true });
return airQuality;
}
catch (HttpRequestException e)
{
Console.WriteLine(e.Message);
Console.WriteLine(e.StackTrace);
_logger?.Warning($"{nameof(OpenMeteoClient)}.GetAirQualityAsync(). Message: {e.Message} StackTrace: {e.StackTrace}");
if (_rethrowExceptions)
throw;
return null;
}
}
Expand Down Expand Up @@ -286,16 +314,35 @@ public string WeathercodeToString(int weathercode)
{
try
{
HttpResponseMessage response = await httpController.Client.GetAsync(MergeUrlWithOptions(_weatherApiUrl, options));
response.EnsureSuccessStatusCode();
var url = MergeUrlWithOptions(_weatherApiUrl, options);
_logger?.Debug($"{nameof(OpenMeteoClient)}.GetElevationAsync(). URL: {url}");
HttpResponseMessage response = await httpController.Client.GetAsync(url);
if(response.IsSuccessStatusCode)
{
WeatherForecast? weatherForecast = await JsonSerializer.DeserializeAsync<WeatherForecast>(await response.Content.ReadAsStreamAsync(), new JsonSerializerOptions() { PropertyNameCaseInsensitive = true });
return weatherForecast;
}

WeatherForecast? weatherForecast = await JsonSerializer.DeserializeAsync<WeatherForecast>(await response.Content.ReadAsStreamAsync(), new JsonSerializerOptions() { PropertyNameCaseInsensitive = true });
return weatherForecast;
ErrorResponse? error = null;
if((int)response.StatusCode >= 400 && (int)response.StatusCode < 500)
{
try
{
error = await JsonSerializer.DeserializeAsync<ErrorResponse>(await response.Content.ReadAsStreamAsync(), new JsonSerializerOptions() { PropertyNameCaseInsensitive = true });
}
catch (Exception e)
{
_logger?.Error($"{nameof(OpenMeteoClient)}.GetWeatherForecastAsync(). Unable to deserialise error response. This exception will be thrown. Message: {e.Message} StackTrace: {e.StackTrace}");
}
}

throw new OpenMeteoClientException(error?.Reason ?? "Exception in OpenMeteoClient", response.StatusCode);
}
catch (HttpRequestException e)
catch (Exception e)
{
Console.WriteLine(e.Message);
Console.WriteLine(e.StackTrace);
_logger?.Warning($"{nameof(OpenMeteoClient)}.GetWeatherForecastAsync(). Message: {e.Message} StackTrace: {e.StackTrace}");
if (_rethrowExceptions)
throw;
return null;
}

Expand All @@ -305,7 +352,10 @@ public string WeathercodeToString(int weathercode)
{
try
{
HttpResponseMessage response = await httpController.Client.GetAsync(MergeUrlWithOptions(_geocodeApiUrl, options));

var url = MergeUrlWithOptions(_geocodeApiUrl, options);
_logger?.Debug($"{nameof(OpenMeteoClient)}.GetGeocodingDataAsync(). URL: {url}");
HttpResponseMessage response = await httpController.Client.GetAsync(url);
response.EnsureSuccessStatusCode();

GeocodingApiResponse? geocodingData = await JsonSerializer.DeserializeAsync<GeocodingApiResponse>(await response.Content.ReadAsStreamAsync(), new JsonSerializerOptions() { PropertyNameCaseInsensitive = true });
Expand All @@ -314,8 +364,32 @@ public string WeathercodeToString(int weathercode)
}
catch (HttpRequestException e)
{
Console.WriteLine("Can't find " + options.Name + ". Please make sure that the name is valid.");
Console.WriteLine(e.Message);
_logger?.Warning($"{nameof(OpenMeteoClient)}.GetGeocodingDataAsync(). Message: {e.Message} StackTrace: {e.StackTrace}");
if (_rethrowExceptions)
throw;
return null;
}
}

private async Task<ElevationApiResponse?> GetElevationAsync(ElevationOptions options)
{
try
{
var url = MergeUrlWithOptions(_elevationApiUrl, options);
_logger?.Debug($"{nameof(OpenMeteoClient)}.GetElevationAsync(). URL: {url}");
HttpResponseMessage response = await httpController.Client.GetAsync(url);
response.EnsureSuccessStatusCode();

ElevationApiResponse? elevationData = await JsonSerializer.DeserializeAsync<ElevationApiResponse>(await response.Content.ReadAsStreamAsync(), new JsonSerializerOptions() { PropertyNameCaseInsensitive = true });

return elevationData;
}
catch (HttpRequestException e)
{
_logger?.Warning($"Can't find elevation for latitude {options.Latitude} & longitude {options.Longitude}. Please make sure that they are valid.");
_logger?.Warning($"Error in {nameof(OpenMeteoClient)}.GetElevationAsync(). Message: {e.Message} StackTrace: {e.StackTrace}");
if (_rethrowExceptions)
throw;
return null;
}
}
Expand Down Expand Up @@ -563,6 +637,18 @@ private string MergeUrlWithOptions(string url, AirQualityOptions options)

return uri.ToString();
}

private string MergeUrlWithOptions(string url, ElevationOptions options)
{
if (options == null) return url;

UriBuilder uri = new UriBuilder(url)
{
Query = $"?latitude={options.Latitude.ToString(CultureInfo.InvariantCulture)}&longitude={options.Longitude.ToString(CultureInfo.InvariantCulture)}"
};

return uri.ToString();
}
}
}

Loading
Loading