diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 3845e675..ffc166db 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -33,9 +33,8 @@ jobs: uses: actions/setup-dotnet@v4 with: dotnet-version: | - 6.0.x - 7.0.x 8.0.x + 9.0.x # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8c37e803..00614b29 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -21,9 +21,8 @@ jobs: uses: actions/setup-dotnet@v4 with: dotnet-version: | - 6.0.x - 7.0.x 8.0.x + 9.0.x - name: Build run: | diff --git a/MaxMind.GeoIP2.Benchmark/MaxMind.GeoIP2.Benchmark.csproj b/MaxMind.GeoIP2.Benchmark/MaxMind.GeoIP2.Benchmark.csproj index af965017..77bfd7d9 100644 --- a/MaxMind.GeoIP2.Benchmark/MaxMind.GeoIP2.Benchmark.csproj +++ b/MaxMind.GeoIP2.Benchmark/MaxMind.GeoIP2.Benchmark.csproj @@ -3,8 +3,8 @@ Benchmark project to validate MaxMind GeoIP2 Database Reader and Web Service Client 5.0.0 - net8.0;net7.0;net6.0;net472 - net8.0;net7.0;net6.0 + net9.0;net8.0;net481 + net9.0;net8.0 MaxMind.GeoIP2.Benchmark Exe ../MaxMind.snk @@ -20,7 +20,7 @@ false false false - 12.0 + 13.0 enable latest true diff --git a/MaxMind.GeoIP2.UnitTests/DeserializationTests.cs b/MaxMind.GeoIP2.UnitTests/DeserializationTests.cs index 678dc4fb..9d4e7d0a 100644 --- a/MaxMind.GeoIP2.UnitTests/DeserializationTests.cs +++ b/MaxMind.GeoIP2.UnitTests/DeserializationTests.cs @@ -107,7 +107,7 @@ private static void CanDeserializeInsightsResponse(InsightsResponse insights) Assert.Equal("004", insights.Traits.MobileNetworkCode); var network = insights.Traits.Network!; - Assert.Equal("1.2.3.0", network.NetworkAddress?.ToString()); + Assert.Equal("1.2.3.0", network.NetworkAddress.ToString()); Assert.Equal(24, network.PrefixLength); Assert.Equal("Blorg", insights.Traits.Organization); diff --git a/MaxMind.GeoIP2.UnitTests/MaxMind.GeoIP2.UnitTests.csproj b/MaxMind.GeoIP2.UnitTests/MaxMind.GeoIP2.UnitTests.csproj index 1196ee85..efee4864 100644 --- a/MaxMind.GeoIP2.UnitTests/MaxMind.GeoIP2.UnitTests.csproj +++ b/MaxMind.GeoIP2.UnitTests/MaxMind.GeoIP2.UnitTests.csproj @@ -3,8 +3,8 @@ Test project to validate MaxMind GeoIP2 Database Reader and Web Service Client 5.0.0 - net8.0;net7.0;net6.0;net472 - net8.0;net7.0;net6.0 + net9.0;net8.0;net481 + net9.0;net8.0 MaxMind.GeoIP2.UnitTests ../MaxMind.snk true @@ -20,7 +20,7 @@ false false false - 12.0 + 13.0 enable latest true @@ -29,10 +29,10 @@ - - - - + + + + runtime; build; native; contentfiles; analyzers all diff --git a/MaxMind.GeoIP2.UnitTests/ResponseHelper.cs b/MaxMind.GeoIP2.UnitTests/ResponseHelper.cs index b7e7b3f5..7f19018a 100644 --- a/MaxMind.GeoIP2.UnitTests/ResponseHelper.cs +++ b/MaxMind.GeoIP2.UnitTests/ResponseHelper.cs @@ -2,122 +2,124 @@ { internal static class ResponseHelper { - public static string InsightsJson = @" - { - ""city"": { - ""confidence"": 76, - ""geoname_id"": 9876, - ""names"": {""en"": ""Minneapolis""} - }, - ""continent"": { - ""code"": ""NA"", - ""geoname_id"": 42, - ""names"": {""en"": ""North America""} - }, - ""country"": { - ""confidence"": 99, - ""iso_code"": ""US"", - ""geoname_id"": 1, - ""names"": {""en"": ""United States of America""} - }, - ""location"": { - ""accuracy_radius"": 1500, - ""average_income"": 50000, - ""latitude"": 44.98, - ""longitude"": 93.2636, - ""metro_code"": 765, - ""population_density"": 100, - ""time_zone"": ""America/Chicago"" - }, - ""postal"": { - ""confidence"": 33, - ""code"": ""55401"" - }, - ""registered_country"": { - ""geoname_id"": 2, - ""is_in_european_union"": true, - ""iso_code"": ""DE"", - ""names"": {""en"": ""Germany""} - }, - ""represented_country"": { - ""geoname_id"": 3, - ""is_in_european_union"": true, - ""iso_code"": ""GB"", - ""names"": {""en"": ""United Kingdom""}, - ""type"": ""military"" - }, - ""subdivisions"": [ - { - ""confidence"": 88, - ""geoname_id"": 574635, - ""iso_code"": ""MN"", - ""names"": {""en"": ""Minnesota""} + public static string InsightsJson = """ + { + "city": { + "confidence": 76, + "geoname_id": 9876, + "names": {"en": "Minneapolis"} }, - {""iso_code"": ""TT""} - ], - ""traits"": { - ""autonomous_system_number"": 1234, - ""autonomous_system_organization"": ""AS Organization"", - ""connection_type"": ""Cable/DSL"", - ""domain"": ""example.com"", - ""ip_address"": ""1.2.3.4"", - ""is_anonymous"": true, - ""is_anonymous_proxy"": true, - ""is_anonymous_vpn"": true, - ""is_anycast"": true, - ""is_hosting_provider"": true, - ""is_public_proxy"": true, - ""is_residential_proxy"": true, - ""is_satellite_provider"": true, - ""is_tor_exit_node"": true, - ""isp"": ""Comcast"", - ""mobile_country_code"": ""310"", - ""mobile_network_code"": ""004"", - ""network"": ""1.2.3.0/24"", - ""organization"": ""Blorg"", - ""static_ip_score"": 1.5, - ""user_count"": 1, - ""user_type"": ""college"" - }, - ""maxmind"": {""queries_remaining"": 11} - }"; + "continent": { + "code": "NA", + "geoname_id": 42, + "names": {"en": "North America"} + }, + "country": { + "confidence": 99, + "iso_code": "US", + "geoname_id": 1, + "names": {"en": "United States of America"} + }, + "location": { + "accuracy_radius": 1500, + "average_income": 50000, + "latitude": 44.98, + "longitude": 93.2636, + "metro_code": 765, + "population_density": 100, + "time_zone": "America/Chicago" + }, + "postal": { + "confidence": 33, + "code": "55401" + }, + "registered_country": { + "geoname_id": 2, + "is_in_european_union": true, + "iso_code": "DE", + "names": {"en": "Germany"} + }, + "represented_country": { + "geoname_id": 3, + "is_in_european_union": true, + "iso_code": "GB", + "names": {"en": "United Kingdom"}, + "type": "military" + }, + "subdivisions": [ + { + "confidence": 88, + "geoname_id": 574635, + "iso_code": "MN", + "names": {"en": "Minnesota"} + }, + {"iso_code": "TT"} + ], + "traits": { + "autonomous_system_number": 1234, + "autonomous_system_organization": "AS Organization", + "connection_type": "Cable/DSL", + "domain": "example.com", + "ip_address": "1.2.3.4", + "is_anonymous": true, + "is_anonymous_proxy": true, + "is_anonymous_vpn": true, + "is_anycast": true, + "is_hosting_provider": true, + "is_public_proxy": true, + "is_residential_proxy": true, + "is_satellite_provider": true, + "is_tor_exit_node": true, + "isp": "Comcast", + "mobile_country_code": "310", + "mobile_network_code": "004", + "network": "1.2.3.0/24", + "organization": "Blorg", + "static_ip_score": 1.5, + "user_count": 1, + "user_type": "college" + }, + "maxmind": {"queries_remaining": 11} + } + """; - public static string CountryJson = @" - { - ""continent"": { - ""code"": ""NA"", - ""geoname_id"": 42, - ""names"": {""en"": ""North America""} - }, - ""country"": { - ""geoname_id"": 1, - ""iso_code"": ""US"", - ""confidence"": 56, - ""names"": {""en"": ""United States""} - }, - ""registered_country"": { - ""geoname_id"": 2, - ""is_in_european_union"": true , - ""iso_code"": ""DE"", - ""names"": {""en"": ""Germany""} - }, - ""represented_country"": { - ""geoname_id"": 4, - ""is_in_european_union"": true , - ""iso_code"": ""GB"", - ""names"": {""en"": ""United Kingdom""}, - ""type"": ""military"" - }, - ""traits"": { - ""ip_address"": ""1.2.3.4"", - ""is_anycast"": true, - ""network"": ""1.2.3.0/24"" + public static string CountryJson = """ + { + "continent": { + "code": "NA", + "geoname_id": 42, + "names": {"en": "North America"} + }, + "country": { + "geoname_id": 1, + "iso_code": "US", + "confidence": 56, + "names": {"en": "United States"} + }, + "registered_country": { + "geoname_id": 2, + "is_in_european_union": true , + "iso_code": "DE", + "names": {"en": "Germany"} + }, + "represented_country": { + "geoname_id": 4, + "is_in_european_union": true , + "iso_code": "GB", + "names": {"en": "United Kingdom"}, + "type": "military" + }, + "traits": { + "ip_address": "1.2.3.4", + "is_anycast": true, + "network": "1.2.3.0/24" + } } - }"; + """; public static string ErrorJson(string code, string message) { - return $@"{{""code"": ""{code}"", ""error"": ""{message}""}}"; + return $$"""{"code": "{{code}}", "error": "{{message}}"}"""; } } } diff --git a/MaxMind.GeoIP2.UnitTests/WebServiceClientTests.cs b/MaxMind.GeoIP2.UnitTests/WebServiceClientTests.cs index c9b4a1ba..a4130bcf 100644 --- a/MaxMind.GeoIP2.UnitTests/WebServiceClientTests.cs +++ b/MaxMind.GeoIP2.UnitTests/WebServiceClientTests.cs @@ -36,43 +36,36 @@ public WebServiceClientTests() public static readonly object[][] TestCases = { #pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously - new object[] {"country", (ClientRunner) (async (c, i) => c.Country(i)), typeof(CountryResponse)}, + ["country", (ClientRunner) (async (c, i) => c.Country(i)), typeof(CountryResponse)], #pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously - new object[] {"city", (ClientRunner) (async (c, i) => c.City(i)), typeof(CityResponse)}, + ["city", (ClientRunner) (async (c, i) => c.City(i)), typeof(CityResponse)], #pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously - new object[] {"insights", (ClientRunner) (async (c, i) => c.Insights(i)), typeof(InsightsResponse)}, + ["insights", (ClientRunner) (async (c, i) => c.Insights(i)), typeof(InsightsResponse)], #pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously - new object[] - {"countryAsync", (ClientRunner) (async (c, i) => await c.CountryAsync(i)), typeof(CountryResponse)}, - new object[] {"cityAsync", (ClientRunner) (async (c, i) => await c.CityAsync(i)), typeof(CityResponse)}, - new object[] - {"insightsAsync", (ClientRunner) (async (c, i) => await c.InsightsAsync(i)), typeof(InsightsResponse)} + ["countryAsync", (ClientRunner) (async (c, i) => await c.CountryAsync(i)), typeof(CountryResponse)], + ["cityAsync", (ClientRunner) (async (c, i) => await c.CityAsync(i)), typeof(CityResponse)], + ["insightsAsync", (ClientRunner) (async (c, i) => await c.InsightsAsync(i)), typeof(InsightsResponse)] }; public delegate Task MeClientRunner(WebServiceClient c); public static readonly object[][] MeTestCases = - { - new object[] - { + [ + [ "country", (MeClientRunner) (c => Task.FromResult(c.Country())), typeof(CountryResponse) - }, - new object[] - { + ], + [ "city", (MeClientRunner) (c => Task.FromResult(c.City())), typeof(CityResponse) - }, - new object[] - { + ], + [ "insights", (MeClientRunner) (c => Task.FromResult(c.Insights())), typeof(InsightsResponse) - }, - new object[] - {"countryAsync", (MeClientRunner) (async c => await c.CountryAsync()), typeof(CountryResponse)}, - new object[] {"cityAsync", (MeClientRunner) (async c => await c.CityAsync()), typeof(CityResponse)}, - new object[] - {"insightsAsync", (MeClientRunner) (async c => await c.InsightsAsync()), typeof(InsightsResponse)} - }; + ], + ["countryAsync", (MeClientRunner) (async c => await c.CountryAsync()), typeof(CountryResponse)], + ["cityAsync", (MeClientRunner) (async c => await c.CityAsync()), typeof(CityResponse)], + ["insightsAsync", (MeClientRunner) (async c => await c.InsightsAsync()), typeof(InsightsResponse)] + ]; private bool _disposed; private WebServiceClient CreateClient(string type, string ipAddress = "1.2.3.4", diff --git a/MaxMind.GeoIP2/Exceptions/HttpException.cs b/MaxMind.GeoIP2/Exceptions/HttpException.cs index c2f3fcca..35d185a9 100644 --- a/MaxMind.GeoIP2/Exceptions/HttpException.cs +++ b/MaxMind.GeoIP2/Exceptions/HttpException.cs @@ -26,9 +26,7 @@ public HttpException(string message, HttpStatusCode httpStatus, Uri uri) : base(message) { HttpStatus = httpStatus; -#pragma warning disable IDE0003 // Mono gets confused if 'this' is missing - this.Uri = uri; -#pragma warning restore IDE0003 + Uri = uri; } /// @@ -42,9 +40,7 @@ public HttpException(string message, HttpStatusCode httpStatus, Uri uri, Excepti : base(message, innerException) { HttpStatus = httpStatus; -#pragma warning disable IDE0003 // Mono gets confused without 'this' - this.Uri = uri; -#pragma warning restore IDE0003 + Uri = uri; } /// diff --git a/MaxMind.GeoIP2/Exceptions/InvalidRequestException.cs b/MaxMind.GeoIP2/Exceptions/InvalidRequestException.cs index 4c6ebd4b..e3fe4057 100644 --- a/MaxMind.GeoIP2/Exceptions/InvalidRequestException.cs +++ b/MaxMind.GeoIP2/Exceptions/InvalidRequestException.cs @@ -25,9 +25,7 @@ public InvalidRequestException(string message, string code, Uri uri) : base(message) { Code = code; -#pragma warning disable IDE0003 // Mono gets confused if 'this' is missing - this.Uri = uri; -#pragma warning restore IDE0003 + Uri = uri; } diff --git a/MaxMind.GeoIP2/Exceptions/PermissionRequiredException.cs b/MaxMind.GeoIP2/Exceptions/PermissionRequiredException.cs index c3886733..aea3fda1 100644 --- a/MaxMind.GeoIP2/Exceptions/PermissionRequiredException.cs +++ b/MaxMind.GeoIP2/Exceptions/PermissionRequiredException.cs @@ -26,7 +26,7 @@ public PermissionRequiredException(string message) : base(message) /// /// Exception message. /// The underlying exception that caused this one. - public PermissionRequiredException(string message, System.Exception innerException) + public PermissionRequiredException(string message, Exception innerException) : base(message, innerException) { } diff --git a/MaxMind.GeoIP2/Http/Client.cs b/MaxMind.GeoIP2/Http/Client.cs index 0859946e..5baa24fa 100644 --- a/MaxMind.GeoIP2/Http/Client.cs +++ b/MaxMind.GeoIP2/Http/Client.cs @@ -50,7 +50,7 @@ public Response Get(Uri uri) var ms = new MemoryStream(); response.Content.ReadAsStream().CopyTo(ms); var content = ms.ToArray(); - var contentType = response.Content.Headers.GetValues("Content-Type")?.FirstOrDefault(); + var contentType = response.Content.Headers.GetValues("Content-Type").FirstOrDefault(); return new Response(uri, response.StatusCode, contentType, content); } @@ -64,7 +64,7 @@ public async Task GetAsync(Uri uri) // paths for async vs sync. Hopefully we can get rid of the sync code at // some point instead. var content = await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false); - var contentType = response.Content.Headers.GetValues("Content-Type")?.FirstOrDefault(); + var contentType = response.Content.Headers.GetValues("Content-Type").FirstOrDefault(); return new Response(uri, response.StatusCode, contentType, content); } diff --git a/MaxMind.GeoIP2/Http/ISyncClient.cs b/MaxMind.GeoIP2/Http/ISyncClient.cs index 006c7f37..8a5d1d48 100644 --- a/MaxMind.GeoIP2/Http/ISyncClient.cs +++ b/MaxMind.GeoIP2/Http/ISyncClient.cs @@ -1,10 +1,11 @@ -#region +#if NETSTANDARD2_0 || NETSTANDARD2_1 + +#region using System; #endregion -#if NETSTANDARD2_0 || NETSTANDARD2_1 namespace MaxMind.GeoIP2.Http { internal interface ISyncClient diff --git a/MaxMind.GeoIP2/Http/Response.cs b/MaxMind.GeoIP2/Http/Response.cs index 464a0068..e4e74237 100644 --- a/MaxMind.GeoIP2/Http/Response.cs +++ b/MaxMind.GeoIP2/Http/Response.cs @@ -19,9 +19,7 @@ public Response(Uri requestUri, HttpStatusCode statusCode, string? contentType, RequestUri = requestUri; StatusCode = statusCode; ContentType = contentType; -#pragma warning disable IDE0003 // Mono gets confused if 'this' is missing - this.Content = content; -#pragma warning restore IDE0003 + Content = content; } internal static object Create() diff --git a/MaxMind.GeoIP2/Http/SyncClient.cs b/MaxMind.GeoIP2/Http/SyncClient.cs index 9bc04325..872568ad 100644 --- a/MaxMind.GeoIP2/Http/SyncClient.cs +++ b/MaxMind.GeoIP2/Http/SyncClient.cs @@ -1,4 +1,6 @@ -#region +#if NETSTANDARD2_0 || NETSTANDARD2_1 + +#region using MaxMind.GeoIP2.Exceptions; using System; @@ -7,8 +9,6 @@ #endregion -#if NETSTANDARD2_0 || NETSTANDARD2_1 - namespace MaxMind.GeoIP2.Http { internal class SyncClient : ISyncClient diff --git a/MaxMind.GeoIP2/MaxMind.GeoIP2.csproj b/MaxMind.GeoIP2/MaxMind.GeoIP2.csproj index 1fed9710..76c915ac 100644 --- a/MaxMind.GeoIP2/MaxMind.GeoIP2.csproj +++ b/MaxMind.GeoIP2/MaxMind.GeoIP2.csproj @@ -3,7 +3,7 @@ MaxMind GeoIP2 Database Reader and Web Service Client 5.2.0 - net8.0;net7.0;net6.0;netstandard2.1;netstandard2.0 + net9.0;net8.0;netstandard2.1;netstandard2.0 true MaxMind.GeoIP2 ../MaxMind.snk @@ -27,7 +27,7 @@ false false false - 12.0 + 13.0 enable latest true @@ -37,12 +37,12 @@ - + - 8.0.5 + 9.0.0 diff --git a/MaxMind.GeoIP2/Responses/AbstractCityResponse.cs b/MaxMind.GeoIP2/Responses/AbstractCityResponse.cs index 5f42f1ce..4f09ffa8 100644 --- a/MaxMind.GeoIP2/Responses/AbstractCityResponse.cs +++ b/MaxMind.GeoIP2/Responses/AbstractCityResponse.cs @@ -87,16 +87,7 @@ protected AbstractCityResponse( /// returns an empty object. /// [JsonIgnore] - public Subdivision MostSpecificSubdivision - { - get - { - if (Subdivisions == null || Subdivisions.Count == 0) - return new Subdivision(); - - return Subdivisions[Subdivisions.Count - 1]; - } - } + public Subdivision MostSpecificSubdivision => Subdivisions.Count == 0 ? new Subdivision() : Subdivisions[Subdivisions.Count - 1]; /// /// Returns a that represents this instance. @@ -107,19 +98,17 @@ public Subdivision MostSpecificSubdivision public override string ToString() { return GetType().Name + " [" - + (City != null ? "City=" + City + ", " : "") - + (Location != null ? "Location=" + Location + ", " : "") - + (Postal != null ? "Postal=" + Postal + ", " : "") - + - (Subdivisions != null - ? "Subdivisions={" + string.Join(",", Subdivisions.Select(s => s.ToString()).ToArray()) + "}, " - : "") - + (Continent != null ? "Continent=" + Continent + ", " : "") - + (Country != null ? "Country=" + Country + ", " : "") - + (RegisteredCountry != null ? "RegisteredCountry=" + RegisteredCountry + ", " : "") - + (RepresentedCountry != null ? "RepresentedCountry=" + RepresentedCountry + ", " : "") - + (Traits != null ? "Traits=" + Traits : "") - + "]"; + + "City=" + City + ", " + + "Location=" + Location + ", " + + "Postal=" + Postal + ", " + + "Subdivisions={" + + string.Join(",", Subdivisions.Select(s => s.ToString()).ToArray()) + "}, " + + "Continent=" + Continent + ", " + + "Country=" + Country + ", " + + "RegisteredCountry=" + RegisteredCountry + ", " + + "RepresentedCountry=" + RepresentedCountry + ", " + + "Traits=" + Traits + + "]"; } /// @@ -130,13 +119,17 @@ protected internal override void SetLocales(IReadOnlyList locales) { locales = locales.ToList(); base.SetLocales(locales); + City.Locales = locales; - if (City != null) - City.Locales = locales; + if (Subdivisions.Count == 0) + { + return; + } - if (Subdivisions == null || Subdivisions.Count == 0) return; foreach (var subdivision in Subdivisions) + { subdivision.Locales = locales; + } } } } diff --git a/MaxMind.GeoIP2/Responses/AbstractCountryResponse.cs b/MaxMind.GeoIP2/Responses/AbstractCountryResponse.cs index 9e45b31b..1446dbbd 100644 --- a/MaxMind.GeoIP2/Responses/AbstractCountryResponse.cs +++ b/MaxMind.GeoIP2/Responses/AbstractCountryResponse.cs @@ -104,12 +104,12 @@ protected AbstractCountryResponse( public override string ToString() { return GetType().Name + " [" - + (Continent != null ? "Continent=" + Continent + ", " : "") - + (Country != null ? "Country=" + Country + ", " : "") - + (RegisteredCountry != null ? "RegisteredCountry=" + RegisteredCountry + ", " : "") - + (RepresentedCountry != null ? "RepresentedCountry=" + RepresentedCountry + ", " : "") - + (Traits != null ? "Traits=" + Traits : "") - + "]"; + + "Continent=" + Continent + ", " + + "Country=" + Country + ", " + + "RegisteredCountry=" + RegisteredCountry + ", " + + "RepresentedCountry=" + RepresentedCountry + ", " + + "Traits=" + Traits + + "]"; } /// @@ -119,17 +119,10 @@ public override string ToString() protected internal override void SetLocales(IReadOnlyList locales) { locales = locales.ToList(); - if (Continent != null) - Continent.Locales = locales; - - if (Country != null) - Country.Locales = locales; - - if (RegisteredCountry != null) - RegisteredCountry.Locales = locales; - - if (RepresentedCountry != null) - RepresentedCountry.Locales = locales; + Continent.Locales = locales; + Country.Locales = locales; + RegisteredCountry.Locales = locales; + RepresentedCountry.Locales = locales; } } } \ No newline at end of file diff --git a/MaxMind.GeoIP2/Responses/IspResponse.cs b/MaxMind.GeoIP2/Responses/IspResponse.cs index 0b39d6c7..8b9feb71 100644 --- a/MaxMind.GeoIP2/Responses/IspResponse.cs +++ b/MaxMind.GeoIP2/Responses/IspResponse.cs @@ -1,7 +1,6 @@ #region using MaxMind.Db; -using System; using System.Text.Json.Serialization; #endregion diff --git a/MaxMind.GeoIP2/WebServiceClient.cs b/MaxMind.GeoIP2/WebServiceClient.cs index b7f9d752..cd9387e0 100644 --- a/MaxMind.GeoIP2/WebServiceClient.cs +++ b/MaxMind.GeoIP2/WebServiceClient.cs @@ -80,6 +80,7 @@ public class WebServiceClient : IGeoIP2WebServicesClient, IDisposable #endif private bool _disposed; private readonly bool _disableHttps; + private readonly JsonSerializerOptions _jsonOptions; private static ProductInfoHeaderValue UserAgent => new("GeoIP2-dotnet", Version); @@ -156,6 +157,8 @@ HttpClient httpClient _locales = (locales == null ? new List { "en" } : new List(locales)).AsReadOnly(); _client = new Client(auth, timeout, UserAgent, httpClient); _disableHttps = disableHttps; + _jsonOptions = new JsonSerializerOptions(); + _jsonOptions.Converters.Add(new NetworkConverter()); #if NETSTANDARD2_0 || NETSTANDARD2_1 _syncClient = new SyncClient(auth, timeout, UserAgent); #endif @@ -352,7 +355,7 @@ private static IPAddress ParseIP(string ipAddress) IPAddress? ip = null; // The "ipAddress != null" is here for backwards compatibility with - // pre-nullable-reference-types code that might possible rely on the + // pre-nullable-reference-types code that might possibly rely on the // undocumented feature of passing a null IP string. if (ipAddress != null && !IPAddress.TryParse(ipAddress, out ip)) { @@ -418,12 +421,9 @@ private T CreateModel(Response response) $"Received a 200 response for {response.RequestUri} but there was no message body.", HttpStatusCode.OK, response.RequestUri); } - try { - var options = new JsonSerializerOptions(); - options.Converters.Add(new NetworkConverter()); - var model = JsonSerializer.Deserialize(response.Content, options); + var model = JsonSerializer.Deserialize(response.Content, _jsonOptions); if (model == null) { throw new HttpException( @@ -443,25 +443,26 @@ private T CreateModel(Response response) private static Exception CreateStatusException(Response response) { var status = (int)response.StatusCode; - if (status >= 400 && status < 500) + switch (status) { - return Create4xxException(response); + case >= 400 and < 500: + return Create4xxException(response); + case >= 500 and < 600: + return new HttpException( + $"Received a server ({status}) error for {response.RequestUri}", + response.StatusCode, response.RequestUri); + default: + { + var errorMessage = + $"Received an unexpected response for {response.RequestUri} (status code: {status})"; + return new HttpException(errorMessage, response.StatusCode, response.RequestUri); + } } - if (status >= 500 && status < 600) - { - return new HttpException( - $"Received a server ({status}) error for {response.RequestUri}", - response.StatusCode, response.RequestUri); - } - - var errorMessage = - $"Received an unexpected response for {response.RequestUri} (status code: {status})"; - return new HttpException(errorMessage, response.StatusCode, response.RequestUri); } private static Exception Create4xxException(Response response) { - if (response.Content == null || response.Content.Length == 0) + if (response.Content.Length == 0) { return new HttpException( $"Received a {response.StatusCode} error for {response.RequestUri} with no body", diff --git a/releasenotes.md b/releasenotes.md index 463470cf..58c479d2 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -1,6 +1,14 @@ GeoIP2 .NET API Release Notes ============================= +5.3.0 +------------------ + +* .NET 6.0 and .NET 7.0 have been removed as targets as they have both + reach their end of support from Microsoft. If you are using these versions, + the .NET Standard 2.1 target should continue working for you. +* .NET 9.0 has been added as a target. + 5.2.0 (2023-12-05) ------------------