From 861368bb297dae67edde7ea8c857ee5cbe937be2 Mon Sep 17 00:00:00 2001 From: MrSmoke <709976+MrSmoke@users.noreply.github.com> Date: Fri, 12 Jan 2024 13:40:22 +1100 Subject: [PATCH 1/2] Enable nullable on RestClient --- .../ClickView.Extensions.RestClient.csproj | 3 +- src/RestClient/RestClient/src/ErrorBody.cs | 2 +- .../src/Extensions/EnumerableExtensions.cs | 2 +- .../src/Extensions/HttpHeadersExtensions.cs | 35 +++++++++---------- .../RestClient/src/Helpers/ErrorHelper.cs | 2 +- .../src/Http/CoreRestClientOptions.cs | 2 +- .../RestClient/src/NotNullWhenAttribute.cs | 17 +++++++++ .../src/Requests/BaseRestClientRequest.cs | 10 +++--- .../src/Requests/RestClientRequest.cs | 2 +- .../src/Responses/RestClientResponse.cs | 6 ++-- src/RestClient/RestClient/src/RestClient.cs | 9 ++--- .../src/Serialization/ISerializer.cs | 4 +-- .../Serialization/NewtonsoftJsonSerializer.cs | 6 ++-- 13 files changed, 59 insertions(+), 41 deletions(-) create mode 100644 src/RestClient/RestClient/src/NotNullWhenAttribute.cs diff --git a/src/RestClient/RestClient/src/ClickView.Extensions.RestClient.csproj b/src/RestClient/RestClient/src/ClickView.Extensions.RestClient.csproj index 4750dd4..b485d14 100644 --- a/src/RestClient/RestClient/src/ClickView.Extensions.RestClient.csproj +++ b/src/RestClient/RestClient/src/ClickView.Extensions.RestClient.csproj @@ -1,8 +1,9 @@ - netstandard2.0;net462 + netstandard2.1;net462 restclient rest http + enable diff --git a/src/RestClient/RestClient/src/ErrorBody.cs b/src/RestClient/RestClient/src/ErrorBody.cs index 6e2f65b..9e5a483 100644 --- a/src/RestClient/RestClient/src/ErrorBody.cs +++ b/src/RestClient/RestClient/src/ErrorBody.cs @@ -2,6 +2,6 @@ namespace ClickView.Extensions.RestClient { public class ErrorBody { - public string Message { get; set; } + public string Message { get; set; } = null!; } } diff --git a/src/RestClient/RestClient/src/Extensions/EnumerableExtensions.cs b/src/RestClient/RestClient/src/Extensions/EnumerableExtensions.cs index 0c6f517..747e27c 100644 --- a/src/RestClient/RestClient/src/Extensions/EnumerableExtensions.cs +++ b/src/RestClient/RestClient/src/Extensions/EnumerableExtensions.cs @@ -5,7 +5,7 @@ public static class EnumerableExtensions { - public static bool TryGetFirstValue(this IEnumerable source, out T value) + public static bool TryGetFirstValue(this IEnumerable source, out T? value) { if (source == null) throw new ArgumentNullException(nameof(source)); diff --git a/src/RestClient/RestClient/src/Extensions/HttpHeadersExtensions.cs b/src/RestClient/RestClient/src/Extensions/HttpHeadersExtensions.cs index 193effc..eea699d 100644 --- a/src/RestClient/RestClient/src/Extensions/HttpHeadersExtensions.cs +++ b/src/RestClient/RestClient/src/Extensions/HttpHeadersExtensions.cs @@ -1,25 +1,24 @@ -namespace ClickView.Extensions.RestClient.Extensions -{ - using System.Net.Http.Headers; +namespace ClickView.Extensions.RestClient.Extensions; + +using System.Net.Http.Headers; - public static class HttpHeadersExtensions +public static class HttpHeadersExtensions +{ + public static bool TryGetFirstHeaderValue(this HttpHeaders headers, string name, out string? value) { - public static bool TryGetFirstHeaderValue(this HttpHeaders headers, string name, out string value) + if (!headers.TryGetValues(name, out var values)) { - if (!headers.TryGetValues(name, out var values)) - { - value = null; - return false; - } - - if (!values.TryGetFirstValue(out var first)) - { - value = null; - return false; - } + value = null; + return false; + } - value = first; - return true; + if (!values.TryGetFirstValue(out var first)) + { + value = null; + return false; } + + value = first; + return true; } } diff --git a/src/RestClient/RestClient/src/Helpers/ErrorHelper.cs b/src/RestClient/RestClient/src/Helpers/ErrorHelper.cs index 84891ae..6ab2ed5 100644 --- a/src/RestClient/RestClient/src/Helpers/ErrorHelper.cs +++ b/src/RestClient/RestClient/src/Helpers/ErrorHelper.cs @@ -7,7 +7,7 @@ public static class ErrorHelper { - public static string GetDefaultErrorMessage(HttpStatusCode httpStatusCode) + public static string? GetDefaultErrorMessage(HttpStatusCode httpStatusCode) { switch (httpStatusCode) { diff --git a/src/RestClient/RestClient/src/Http/CoreRestClientOptions.cs b/src/RestClient/RestClient/src/Http/CoreRestClientOptions.cs index e7a075c..a5e648a 100644 --- a/src/RestClient/RestClient/src/Http/CoreRestClientOptions.cs +++ b/src/RestClient/RestClient/src/Http/CoreRestClientOptions.cs @@ -5,6 +5,6 @@ namespace ClickView.Extensions.RestClient.Http public class CoreRestClientOptions { public CompressionMethod CompressionMethod { get; set; } = CompressionMethod.None; - public IAuthenticator Authenticator { get; set; } = null; + public IAuthenticator? Authenticator { get; set; } = null; } } diff --git a/src/RestClient/RestClient/src/NotNullWhenAttribute.cs b/src/RestClient/RestClient/src/NotNullWhenAttribute.cs new file mode 100644 index 0000000..76ff1d6 --- /dev/null +++ b/src/RestClient/RestClient/src/NotNullWhenAttribute.cs @@ -0,0 +1,17 @@ +#if NETFRAMEWORK +namespace System.Diagnostics.CodeAnalysis; + +using System; + +internal sealed class NotNullWhenAttribute : Attribute +{ + /// Initializes the attribute with the specified return value condition. + /// + /// The return value condition. If the method returns this value, the associated parameter will not be null. + /// + public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; + + /// Gets the return value condition. + public bool ReturnValue { get; } +} +#endif diff --git a/src/RestClient/RestClient/src/Requests/BaseRestClientRequest.cs b/src/RestClient/RestClient/src/Requests/BaseRestClientRequest.cs index d97d686..23b0823 100644 --- a/src/RestClient/RestClient/src/Requests/BaseRestClientRequest.cs +++ b/src/RestClient/RestClient/src/Requests/BaseRestClientRequest.cs @@ -2,6 +2,7 @@ namespace ClickView.Extensions.RestClient.Requests { using System; using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Net; @@ -28,7 +29,7 @@ protected BaseRestClientRequest(HttpMethod method, string resource) public ISerializer Serializer { internal get; set; } = NewtonsoftJsonSerializer.Instance; - internal HttpContent Content { get; set; } + internal HttpContent? Content { get; set; } /// /// Set to true if we should throw an exception on 404 @@ -119,7 +120,6 @@ internal async Task GetResponseAsync(HttpResponseMessage message) if (error != null) { HandleError(error); - response.Error = error; } @@ -128,7 +128,7 @@ internal async Task GetResponseAsync(HttpResponseMessage message) protected abstract Task ParseResponseAsync(HttpResponseMessage message); - protected virtual bool TryParseErrorBody(string content, out ErrorBody error) + protected virtual bool TryParseErrorBody(string content, [NotNullWhen(true)] out ErrorBody? error) { error = null; return false; @@ -142,7 +142,7 @@ protected virtual ErrorBody GetDefaultErrorBody(HttpStatusCode httpStatusCode, s }; } - protected async Task GetErrorAsync(HttpResponseMessage message) + protected async Task GetErrorAsync(HttpResponseMessage message) { if (message == null) throw new ArgumentNullException(nameof(message)); @@ -170,7 +170,7 @@ protected virtual void HandleError(Error error) throw ErrorHelper.GetErrorException(error); } - protected T Deserialize(string input) + protected T? Deserialize(string input) { try { diff --git a/src/RestClient/RestClient/src/Requests/RestClientRequest.cs b/src/RestClient/RestClient/src/Requests/RestClientRequest.cs index fad0afb..47d9e4e 100644 --- a/src/RestClient/RestClient/src/Requests/RestClientRequest.cs +++ b/src/RestClient/RestClient/src/Requests/RestClientRequest.cs @@ -19,7 +19,7 @@ protected override async Task> ParseResponseAsync(Http return new RestClientResponse(message, Deserialize(str)); } - protected TData Deserialize(string input) + protected TData? Deserialize(string input) { return Deserialize(input); } diff --git a/src/RestClient/RestClient/src/Responses/RestClientResponse.cs b/src/RestClient/RestClient/src/Responses/RestClientResponse.cs index cdc8bbe..dcc2d5d 100644 --- a/src/RestClient/RestClient/src/Responses/RestClientResponse.cs +++ b/src/RestClient/RestClient/src/Responses/RestClientResponse.cs @@ -13,17 +13,17 @@ public RestClientResponse(HttpResponseMessage message) } public HttpStatusCode HttpStatusCode { get; } - public Error Error { get; internal set; } + public Error? Error { get; internal set; } public HttpResponseHeaders Headers { get; } } public class RestClientResponse : RestClientResponse { - public RestClientResponse(HttpResponseMessage message, T data) : base(message) + public RestClientResponse(HttpResponseMessage message, T? data) : base(message) { Data = data; } - public T Data { get; internal set; } + public T? Data { get; internal set; } } } diff --git a/src/RestClient/RestClient/src/RestClient.cs b/src/RestClient/RestClient/src/RestClient.cs index ce679df..3b72d51 100644 --- a/src/RestClient/RestClient/src/RestClient.cs +++ b/src/RestClient/RestClient/src/RestClient.cs @@ -12,7 +12,7 @@ public class RestClient { - private readonly Uri _baseAddress; + private readonly Uri? _baseAddress; private readonly HttpClient _httpClient; private readonly CoreRestClientOptions _options; @@ -21,7 +21,7 @@ public class RestClient /// /// /// - public RestClient(Uri baseAddress, RestClientOptions options = null) + public RestClient(Uri baseAddress, RestClientOptions? options = null) { _baseAddress = baseAddress ?? throw new ArgumentNullException(nameof(baseAddress)); @@ -36,10 +36,11 @@ public RestClient(Uri baseAddress, RestClientOptions options = null) /// /// /// - public RestClient(HttpClient httpClient, CoreRestClientOptions options = null) + public RestClient(HttpClient httpClient, CoreRestClientOptions? options = null) { _httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient)); _options = options ?? RestClientOptions.Default; + _baseAddress = null; } /// @@ -48,7 +49,7 @@ public RestClient(HttpClient httpClient, CoreRestClientOptions options = null) /// /// /// - public RestClient(Uri baseAddress, HttpClient httpClient, CoreRestClientOptions options = null) + public RestClient(Uri baseAddress, HttpClient httpClient, CoreRestClientOptions? options = null) : this(httpClient, options) { _baseAddress = baseAddress ?? throw new ArgumentNullException(nameof(baseAddress)); diff --git a/src/RestClient/RestClient/src/Serialization/ISerializer.cs b/src/RestClient/RestClient/src/Serialization/ISerializer.cs index 3ca91a0..118773c 100644 --- a/src/RestClient/RestClient/src/Serialization/ISerializer.cs +++ b/src/RestClient/RestClient/src/Serialization/ISerializer.cs @@ -8,7 +8,7 @@ public interface ISerializer string Serialize(object obj); - T Deserialize(string input); - object Deserialize(string input, Type type); + T? Deserialize(string input); + object? Deserialize(string input, Type type); } } diff --git a/src/RestClient/RestClient/src/Serialization/NewtonsoftJsonSerializer.cs b/src/RestClient/RestClient/src/Serialization/NewtonsoftJsonSerializer.cs index 6855ebb..fc7d2cb 100644 --- a/src/RestClient/RestClient/src/Serialization/NewtonsoftJsonSerializer.cs +++ b/src/RestClient/RestClient/src/Serialization/NewtonsoftJsonSerializer.cs @@ -7,7 +7,7 @@ public class NewtonsoftJsonSerializer : ISerializer { public static readonly ISerializer Instance = new NewtonsoftJsonSerializer(); - private readonly JsonSerializerSettings _jsonSerializerSettings; + private readonly JsonSerializerSettings? _jsonSerializerSettings; public NewtonsoftJsonSerializer() { @@ -27,12 +27,12 @@ public string Serialize(object obj) return JsonConvert.SerializeObject(obj, _jsonSerializerSettings); } - public T Deserialize(string input) + public T? Deserialize(string input) { return JsonConvert.DeserializeObject(input, _jsonSerializerSettings); } - public object Deserialize(string input, Type type) + public object? Deserialize(string input, Type type) { return JsonConvert.DeserializeObject(input, type, _jsonSerializerSettings); } From 7c98e4bbebe0dd1bfc3d2bb27c37cfa74de347c5 Mon Sep 17 00:00:00 2001 From: MrSmoke <709976+MrSmoke@users.noreply.github.com> Date: Fri, 12 Jan 2024 13:42:57 +1100 Subject: [PATCH 2/2] enable nullable on tests --- .../test/ClickView.Extensions.RestClient.Tests.csproj | 1 + src/RestClient/RestClient/test/RestClientTests.cs | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/RestClient/RestClient/test/ClickView.Extensions.RestClient.Tests.csproj b/src/RestClient/RestClient/test/ClickView.Extensions.RestClient.Tests.csproj index a85ecd3..14e0420 100644 --- a/src/RestClient/RestClient/test/ClickView.Extensions.RestClient.Tests.csproj +++ b/src/RestClient/RestClient/test/ClickView.Extensions.RestClient.Tests.csproj @@ -3,6 +3,7 @@ net6.0 false + enable diff --git a/src/RestClient/RestClient/test/RestClientTests.cs b/src/RestClient/RestClient/test/RestClientTests.cs index a8f4796..499a87b 100644 --- a/src/RestClient/RestClient/test/RestClientTests.cs +++ b/src/RestClient/RestClient/test/RestClientTests.cs @@ -22,7 +22,7 @@ public async Task ExecuteAsync_UsesBaseAddress() .Setup>( "SendAsync", ItExpr.Is(message => - message.RequestUri.Equals(new Uri("http://clickview.com.au/v1/test"))), + message.RequestUri!.Equals(new Uri("http://clickview.com.au/v1/test"))), ItExpr.IsAny() ) .ReturnsAsync(new HttpResponseMessage @@ -53,7 +53,7 @@ public async Task ExecuteAsync_UsesBaseAddressOverHttpClientBaseAddress() .Setup>( "SendAsync", ItExpr.Is(message => - message.RequestUri.Equals(new Uri("http://clickview.com.au/v1/test"))), + message.RequestUri!.Equals(new Uri("http://clickview.com.au/v1/test"))), ItExpr.IsAny() ) .ReturnsAsync(new HttpResponseMessage @@ -87,7 +87,7 @@ public async Task ExecuteAsync_UsesHttpClientBaseAddress() .Setup>( "SendAsync", ItExpr.Is(message => - message.RequestUri.Equals(new Uri("https://hello.hello/test"))), + message.RequestUri!.Equals(new Uri("https://hello.hello/test"))), ItExpr.IsAny() ) .ReturnsAsync(new HttpResponseMessage @@ -121,7 +121,7 @@ public async Task ExecuteAsync_AbsoluteUriRequest() .Setup>( "SendAsync", ItExpr.Is(message => - message.RequestUri.Equals(new Uri("https://clockview.clocks/test"))), + message.RequestUri!.Equals(new Uri("https://clockview.clocks/test"))), ItExpr.IsAny() ) .ReturnsAsync(new HttpResponseMessage @@ -159,4 +159,4 @@ public async Task ExecuteAsync_NoBaseAddress_ThrowsInvalidOperationException() await Assert.ThrowsAsync(() => client.ExecuteAsync(request)); } } -} \ No newline at end of file +}