diff --git a/.editorconfig b/.editorconfig index b3d87c9d..c05bd66d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -4,16 +4,16 @@ # https://docs.microsoft.com/en-us/visualstudio/ide/create-portable-custom-editor-options # .NET coding convention settings for EditorConfig -# https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference?view=vs-2019 +# https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference # Language conventions -# https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-language-conventions?view=vs-2019 +# https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-language-conventions # Formatting conventions -# https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-formatting-conventions?view=vs-2019 +# https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-formatting-conventions # .NET naming conventions for EditorConfig -# https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-naming-conventions?view=vs-2019 +# https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-naming-conventions # Top-most EditorConfig file root = true @@ -26,6 +26,9 @@ indent_style = space indent_size = 2 trim_trailing_whitespace = true +[*.json] +insert_final_newline = false + [*.cs] indent_size = 4 @@ -91,8 +94,8 @@ csharp_style_var_elsewhere = true:suggestion # C# code style settings - Expression-bodied members # https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-language-conventions?view=vs-2019#expression-bodied-members -csharp_style_expression_bodied_methods = when_on_single_line:warning -csharp_style_expression_bodied_constructors = false:suggestion +csharp_style_expression_bodied_methods = when_on_single_line:suggestion +csharp_style_expression_bodied_constructors = false:warning csharp_style_expression_bodied_operators = when_on_single_line:warning csharp_style_expression_bodied_properties = when_on_single_line:warning csharp_style_expression_bodied_indexers = when_on_single_line:warning @@ -120,7 +123,7 @@ csharp_style_conditional_delegate_call = true:warning # C# code style settings - Code block preferences # https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-language-conventions?view=vs-2019#code-block-preferences -csharp_prefer_braces = false:suggestion +csharp_prefer_braces = when_multiline:suggestion # C# code style - Unused value preferences # https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-language-conventions?view=vs-2019#unused-value-preferences @@ -129,8 +132,8 @@ csharp_style_unused_value_assignment_preference = discard_variable:suggestion # C# code style - Index and range preferences # https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-language-conventions?view=vs-2019#index-and-range-preferences -csharp_style_prefer_index_operator = true:warning -csharp_style_prefer_range_operator = true:warning +csharp_style_prefer_index_operator = true:suggestion +csharp_style_prefer_range_operator = true:suggestion # C# code style - Miscellaneous preferences # https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-language-conventions?view=vs-2019#miscellaneous-preferences @@ -138,8 +141,8 @@ csharp_style_deconstructed_variable_declaration = true:suggestion csharp_style_pattern_local_over_anonymous_function = true:suggestion csharp_using_directive_placement = outside_namespace:warning csharp_prefer_static_local_function = true:suggestion -csharp_prefer_simple_using_statement = false:suggestion -csharp_style_prefer_switch_expression = true:suggestion +csharp_prefer_simple_using_statement = true:warning +csharp_style_prefer_switch_expression = true:warning # .NET formatting settings - Organize using directives # https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-formatting-conventions?view=vs-2019#organize-using-directives @@ -260,3 +263,27 @@ dotnet_naming_rule.async_methods_end_in_async.severity = warning # ReSharper: Configure await configure_await_analysis_mode = library + +# Remove unnecessary import https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0005 +dotnet_diagnostic.IDE0005.severity = error + +# Enforce formatting https://docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/formatting-rules#rule-id-ide0055-fix-formatting +dotnet_diagnostic.IDE0055.severity = error + +# https://github.com/JosefPihrt/Roslynator/blob/master/docs/analyzers/RCS0060.md +dotnet_diagnostic.RCS0060.severity = warning +roslynator_blank_line_after_file_scoped_namespace_declaration = true + +# https://github.com/JosefPihrt/Roslynator/blob/main/docs/analyzers/RCS1080.md +dotnet_diagnostic.RCS1080.severity = warning + +# ConfigureAwait https://github.com/JosefPihrt/Roslynator/blob/master/docs/analyzers/RCS1090.md +dotnet_diagnostic.RCS1090.severity = warning +roslynator_configure_await = true + +# https://github.com/JosefPihrt/Roslynator/blob/master/docs/analyzers/RCS1102.md +# TODO: NullabilityInfo issue in Patching.cs in internal class SR +dotnet_diagnostic.RCS1102.severity = suggestion + +# https://github.com/JosefPihrt/Roslynator/blob/master/docs/analyzers/RCS1194.md +dotnet_diagnostic.RCS1194.severity = suggestion diff --git a/examples/GraphQL.Client.Example/PersonAndFilmsResponse.cs b/examples/GraphQL.Client.Example/PersonAndFilmsResponse.cs index 7dbd22b5..3a66edc7 100644 --- a/examples/GraphQL.Client.Example/PersonAndFilmsResponse.cs +++ b/examples/GraphQL.Client.Example/PersonAndFilmsResponse.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; - namespace GraphQL.Client.Example; public class PersonAndFilmsResponse diff --git a/examples/GraphQL.Client.Example/Program.cs b/examples/GraphQL.Client.Example/Program.cs index b1f4d2ac..83f8da0a 100644 --- a/examples/GraphQL.Client.Example/Program.cs +++ b/examples/GraphQL.Client.Example/Program.cs @@ -1,7 +1,4 @@ -using System; -using System.Linq; using System.Text.Json; -using System.Threading.Tasks; using GraphQL.Client.Http; using GraphQL.Client.Serializer.Newtonsoft; diff --git a/src/GraphQL.Client.Abstractions/Utilities/StringExtensions.cs b/src/GraphQL.Client.Abstractions/Utilities/StringExtensions.cs index f751adb8..cc99a85e 100644 --- a/src/GraphQL.Client.Abstractions/Utilities/StringExtensions.cs +++ b/src/GraphQL.Client.Abstractions/Utilities/StringExtensions.cs @@ -1,4 +1,4 @@ -namespace GraphQL.Client.Abstractions.Utilities; +namespace GraphQL.Client.Abstractions.Utilities; /// /// Copied from https://github.com/jquense/StringUtils diff --git a/src/GraphQL.Client.Abstractions/Utilities/StringUtils.cs b/src/GraphQL.Client.Abstractions/Utilities/StringUtils.cs index 27fbf992..87047f79 100644 --- a/src/GraphQL.Client.Abstractions/Utilities/StringUtils.cs +++ b/src/GraphQL.Client.Abstractions/Utilities/StringUtils.cs @@ -1,4 +1,4 @@ -using System.Text.RegularExpressions; +using System.Text.RegularExpressions; namespace GraphQL.Client.Abstractions.Utilities; diff --git a/src/GraphQL.Client.Serializer.Newtonsoft/NewtonsoftJsonSerializer.cs b/src/GraphQL.Client.Serializer.Newtonsoft/NewtonsoftJsonSerializer.cs index 63cc6de3..0cfd14b1 100644 --- a/src/GraphQL.Client.Serializer.Newtonsoft/NewtonsoftJsonSerializer.cs +++ b/src/GraphQL.Client.Serializer.Newtonsoft/NewtonsoftJsonSerializer.cs @@ -8,7 +8,7 @@ namespace GraphQL.Client.Serializer.Newtonsoft; public class NewtonsoftJsonSerializer : IGraphQLWebsocketJsonSerializer { - public static JsonSerializerSettings DefaultJsonSerializerSettings => new JsonSerializerSettings + public static JsonSerializerSettings DefaultJsonSerializerSettings => new() { ContractResolver = new CamelCasePropertyNamesContractResolver { IgnoreIsSpecifiedMembers = true }, MissingMemberHandling = MissingMemberHandling.Ignore, @@ -34,7 +34,7 @@ public NewtonsoftJsonSerializer(JsonSerializerSettings jsonSerializerSettings) public byte[] SerializeToBytes(GraphQLWebSocketRequest request) { - var json = JsonConvert.SerializeObject(request, JsonSerializerSettings); + string json = JsonConvert.SerializeObject(request, JsonSerializerSettings); return Encoding.UTF8.GetBytes(json); } diff --git a/src/GraphQL.Client.Serializer.SystemTextJson/ConstantCaseJsonNamingPolicy.cs b/src/GraphQL.Client.Serializer.SystemTextJson/ConstantCaseJsonNamingPolicy.cs index 680503a6..acc7f9b1 100644 --- a/src/GraphQL.Client.Serializer.SystemTextJson/ConstantCaseJsonNamingPolicy.cs +++ b/src/GraphQL.Client.Serializer.SystemTextJson/ConstantCaseJsonNamingPolicy.cs @@ -3,7 +3,7 @@ namespace GraphQL.Client.Serializer.SystemTextJson; -public class ConstantCaseJsonNamingPolicy: JsonNamingPolicy +public class ConstantCaseJsonNamingPolicy : JsonNamingPolicy { public override string ConvertName(string name) => name.ToConstantCase(); } diff --git a/src/GraphQL.Client.Serializer.SystemTextJson/ErrorPathConverter.cs b/src/GraphQL.Client.Serializer.SystemTextJson/ErrorPathConverter.cs index e325dccb..b50a8591 100644 --- a/src/GraphQL.Client.Serializer.SystemTextJson/ErrorPathConverter.cs +++ b/src/GraphQL.Client.Serializer.SystemTextJson/ErrorPathConverter.cs @@ -7,13 +7,13 @@ public class ErrorPathConverter : JsonConverter { public override ErrorPath Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => - new ErrorPath(ReadArray(ref reader)); + new(ReadArray(ref reader)); public override void Write(Utf8JsonWriter writer, ErrorPath value, JsonSerializerOptions options) => throw new NotImplementedException( "This converter currently is only intended to be used to read a JSON object into a strongly-typed representation."); - - private IEnumerable ReadArray(ref Utf8JsonReader reader) + + private static IEnumerable ReadArray(ref Utf8JsonReader reader) { if (reader.TokenType != JsonTokenType.StartArray) { @@ -33,7 +33,7 @@ public override void Write(Utf8JsonWriter writer, ErrorPath value, JsonSerialize return array; } - private object? ReadValue(ref Utf8JsonReader reader) + private static object? ReadValue(ref Utf8JsonReader reader) => reader.TokenType switch { JsonTokenType.None => null, diff --git a/src/GraphQL.Client.Serializer.SystemTextJson/MapConverter.cs b/src/GraphQL.Client.Serializer.SystemTextJson/MapConverter.cs index 66d4aead..78eef361 100644 --- a/src/GraphQL.Client.Serializer.SystemTextJson/MapConverter.cs +++ b/src/GraphQL.Client.Serializer.SystemTextJson/MapConverter.cs @@ -22,7 +22,7 @@ private static TDictionary ReadDictionary(ref Utf8JsonReader reader { if (reader.TokenType != JsonTokenType.StartObject) throw new JsonException(); - + while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) @@ -60,7 +60,7 @@ private static List ReadArray(ref Utf8JsonReader reader) return result; } - + private static object? ReadValue(ref Utf8JsonReader reader) => reader.TokenType switch { @@ -74,6 +74,4 @@ private static List ReadArray(ref Utf8JsonReader reader) JsonTokenType.None => null, _ => throw new InvalidOperationException($"Unexpected value kind: {reader.TokenType}") }; - - } diff --git a/src/GraphQL.Client.Serializer.SystemTextJson/SystemTextJsonSerializer.cs b/src/GraphQL.Client.Serializer.SystemTextJson/SystemTextJsonSerializer.cs index 4fa66c64..232fa421 100644 --- a/src/GraphQL.Client.Serializer.SystemTextJson/SystemTextJsonSerializer.cs +++ b/src/GraphQL.Client.Serializer.SystemTextJson/SystemTextJsonSerializer.cs @@ -10,7 +10,7 @@ public class SystemTextJsonSerializer : IGraphQLWebsocketJsonSerializer public static JsonSerializerOptions DefaultJsonSerializerOptions => new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, - Converters = { new JsonStringEnumConverter(new ConstantCaseJsonNamingPolicy(), false)} + Converters = { new JsonStringEnumConverter(new ConstantCaseJsonNamingPolicy(), false) } }.SetupImmutableConverter(); public JsonSerializerOptions Options { get; } diff --git a/src/GraphQL.Client/GraphQLHttpClient.cs b/src/GraphQL.Client/GraphQLHttpClient.cs index eda4b6f9..e42cd678 100644 --- a/src/GraphQL.Client/GraphQLHttpClient.cs +++ b/src/GraphQL.Client/GraphQLHttpClient.cs @@ -77,12 +77,9 @@ public GraphQLHttpClient(GraphQLHttpClientOptions options, IGraphQLWebsocketJson /// public async Task> SendQueryAsync(GraphQLRequest request, CancellationToken cancellationToken = default) { - if (Options.UseWebSocketForQueriesAndMutations || - !(Options.WebSocketEndPoint is null) && Options.EndPoint is null || - Options.EndPoint.HasWebSocketScheme()) - return await GraphQlHttpWebSocket.SendRequest(request, cancellationToken).ConfigureAwait(false); - - return await SendHttpRequestAsync(request, cancellationToken).ConfigureAwait(false); + return Options.UseWebSocketForQueriesAndMutations || Options.WebSocketEndPoint is not null && Options.EndPoint is null || Options.EndPoint.HasWebSocketScheme() + ? await GraphQlHttpWebSocket.SendRequest(request, cancellationToken).ConfigureAwait(false) + : await SendHttpRequestAsync(request, cancellationToken).ConfigureAwait(false); } /// @@ -132,22 +129,23 @@ private async Task> SendHttpRequestAsync response, HttpResponseHeaders resp public static class GraphQLResponseExtensions { - public static GraphQLHttpResponse ToGraphQLHttpResponse(this GraphQLResponse response, HttpResponseHeaders responseHeaders, HttpStatusCode statusCode) => new GraphQLHttpResponse(response, responseHeaders, statusCode); + public static GraphQLHttpResponse ToGraphQLHttpResponse(this GraphQLResponse response, HttpResponseHeaders responseHeaders, HttpStatusCode statusCode) => new(response, responseHeaders, statusCode); /// /// Casts to . Throws if the cast fails. diff --git a/src/GraphQL.Client/UriExtensions.cs b/src/GraphQL.Client/UriExtensions.cs index 47f5841c..54e623b7 100644 --- a/src/GraphQL.Client/UriExtensions.cs +++ b/src/GraphQL.Client/UriExtensions.cs @@ -8,7 +8,7 @@ public static class UriExtensions /// /// public static bool HasWebSocketScheme(this Uri? uri) => - !(uri is null) && + uri is not null && (uri.Scheme.Equals("wss", StringComparison.OrdinalIgnoreCase) || uri.Scheme.Equals("ws", StringComparison.OrdinalIgnoreCase)); /// @@ -33,6 +33,6 @@ public static Uri GetWebSocketUri(this Uri uri) else throw new NotSupportedException($"cannot infer websocket uri from uri scheme {uri.Scheme}"); - return new UriBuilder(uri){Scheme = webSocketScheme}.Uri; + return new UriBuilder(uri) { Scheme = webSocketScheme }.Uri; } } diff --git a/src/GraphQL.Client/Websocket/GraphQLHttpWebSocket.cs b/src/GraphQL.Client/Websocket/GraphQLHttpWebSocket.cs index 1afa6b98..c85a92a3 100644 --- a/src/GraphQL.Client/Websocket/GraphQLHttpWebSocket.cs +++ b/src/GraphQL.Client/Websocket/GraphQLHttpWebSocket.cs @@ -18,12 +18,11 @@ internal class GraphQLHttpWebSocket : IDisposable private readonly Uri _webSocketUri; private readonly GraphQLHttpClient _client; private readonly ArraySegment _buffer; - private readonly CancellationTokenSource _internalCancellationTokenSource = new CancellationTokenSource(); + private readonly CancellationTokenSource _internalCancellationTokenSource = new(); private readonly CancellationToken _internalCancellationToken; - private readonly Subject _requestSubject = new Subject(); - private readonly Subject _exceptionSubject = new Subject(); - private readonly BehaviorSubject _stateSubject = - new BehaviorSubject(GraphQLWebsocketConnectionState.Disconnected); + private readonly Subject _requestSubject = new(); + private readonly Subject _exceptionSubject = new(); + private readonly BehaviorSubject _stateSubject = new(GraphQLWebsocketConnectionState.Disconnected); private readonly IDisposable _requestSubscription; private int _connectionAttempt = 0; @@ -32,12 +31,12 @@ internal class GraphQLHttpWebSocket : IDisposable private GraphQLHttpClientOptions Options => _client.Options; private Task _initializeWebSocketTask = Task.CompletedTask; - private readonly object _initializeLock = new object(); + private readonly object _initializeLock = new(); #if NETFRAMEWORK - private WebSocket _clientWebSocket = null; + private WebSocket _clientWebSocket; #else - private ClientWebSocket _clientWebSocket = null; + private ClientWebSocket _clientWebSocket; #endif #endregion @@ -93,7 +92,7 @@ public IObservable> CreateSubscriptionStream Observable.Create>(async observer => { - Debug.WriteLine($"Create observable thread id: {Thread.CurrentThread.ManagedThreadId}"); + Debug.WriteLine($"Create observable thread id: {Environment.CurrentManagedThreadId}"); var preprocessedRequest = await _client.Options.PreprocessRequest(request, _client).ConfigureAwait(false); var startRequest = new GraphQLWebSocketRequest @@ -123,7 +122,7 @@ public IObservable> CreateSubscriptionStream( response.MessageBytes); @@ -207,7 +206,7 @@ public IObservable> CreateSubscriptionStream> CreateSubscriptionStream, Exception>>(); + } else { - Debug.WriteLine($"Catch handler thread id: {Thread.CurrentThread.ManagedThreadId}"); + Debug.WriteLine($"Catch handler thread id: {Environment.CurrentManagedThreadId}"); return Observable.Throw, Exception>>(e); } } @@ -239,12 +240,12 @@ public IObservable> CreateSubscriptionStream {t.Item2}"); + Debug.WriteLine($"unwrap exception thread id: {Environment.CurrentManagedThreadId} => {t.Item2}"); return Observable.Throw>(t.Item2); } if (t.Item1 == null) { - Debug.WriteLine($"empty item thread id: {Thread.CurrentThread.ManagedThreadId}"); + Debug.WriteLine($"empty item thread id: {Environment.CurrentManagedThreadId}"); return Observable.Empty>(); } return Observable.Return(t.Item1); @@ -342,7 +343,7 @@ private async Task SendWebSocketRequestAsync(GraphQLWebSocketRequest reque private async Task SendWebSocketMessageAsync(GraphQLWebSocketRequest request, CancellationToken cancellationToken = default) { - var requestBytes = _client.JsonSerializer.SerializeToBytes(request); + byte[] requestBytes = _client.JsonSerializer.SerializeToBytes(request); await _clientWebSocket.SendAsync( new ArraySegment(requestBytes), WebSocketMessageType.Text, @@ -364,7 +365,9 @@ public Task InitializeWebSocket() if (_initializeWebSocketTask != null && !_initializeWebSocketTask.IsFaulted && !_initializeWebSocketTask.IsCompleted) + { return _initializeWebSocketTask; + } // if the websocket is open, return a completed task if (_clientWebSocket != null && _clientWebSocket.State == WebSocketState.Open) @@ -374,24 +377,27 @@ public Task InitializeWebSocket() _clientWebSocket?.Dispose(); #if NETFRAMEWORK - // fix websocket not supported on win 7 using - // https://github.com/PingmanTools/System.Net.WebSockets.Client.Managed - _clientWebSocket = SystemClientWebSocket.CreateClientWebSocket(); - switch (_clientWebSocket) { - case ClientWebSocket nativeWebSocket: - nativeWebSocket.Options.AddSubProtocol("graphql-ws"); - nativeWebSocket.Options.ClientCertificates = ((HttpClientHandler)Options.HttpMessageHandler).ClientCertificates; - nativeWebSocket.Options.UseDefaultCredentials = ((HttpClientHandler)Options.HttpMessageHandler).UseDefaultCredentials; + // fix websocket not supported on win 7 using + // https://github.com/PingmanTools/System.Net.WebSockets.Client.Managed + _clientWebSocket = SystemClientWebSocket.CreateClientWebSocket(); + switch (_clientWebSocket) + { + case ClientWebSocket nativeWebSocket: + nativeWebSocket.Options.AddSubProtocol("graphql-ws"); + nativeWebSocket.Options.ClientCertificates = ((HttpClientHandler)Options.HttpMessageHandler).ClientCertificates; + nativeWebSocket.Options.UseDefaultCredentials = ((HttpClientHandler)Options.HttpMessageHandler).UseDefaultCredentials; Options.ConfigureWebsocketOptions(nativeWebSocket.Options); break; - case System.Net.WebSockets.Managed.ClientWebSocket managedWebSocket: - managedWebSocket.Options.AddSubProtocol("graphql-ws"); - managedWebSocket.Options.ClientCertificates = ((HttpClientHandler)Options.HttpMessageHandler).ClientCertificates; - managedWebSocket.Options.UseDefaultCredentials = ((HttpClientHandler)Options.HttpMessageHandler).UseDefaultCredentials; + + case System.Net.WebSockets.Managed.ClientWebSocket managedWebSocket: + managedWebSocket.Options.AddSubProtocol("graphql-ws"); + managedWebSocket.Options.ClientCertificates = ((HttpClientHandler)Options.HttpMessageHandler).ClientCertificates; + managedWebSocket.Options.UseDefaultCredentials = ((HttpClientHandler)Options.HttpMessageHandler).UseDefaultCredentials; break; - default: - throw new NotSupportedException($"unknown websocket type {_clientWebSocket.GetType().Name}"); - } + + default: + throw new NotSupportedException($"unknown websocket type {_clientWebSocket.GetType().Name}"); + } #else _clientWebSocket = new ClientWebSocket(); _clientWebSocket.Options.AddSubProtocol("graphql-ws"); @@ -437,7 +443,7 @@ private async Task ConnectAsync(CancellationToken token) { await BackOff().ConfigureAwait(false); _stateSubject.OnNext(GraphQLWebsocketConnectionState.Connecting); - Debug.WriteLine($"opening websocket {_clientWebSocket.GetHashCode()} (thread {Thread.CurrentThread.ManagedThreadId})"); + Debug.WriteLine($"opening websocket {_clientWebSocket.GetHashCode()} (thread {Environment.CurrentManagedThreadId})"); await _clientWebSocket.ConnectAsync(_webSocketUri, token).ConfigureAwait(false); _stateSubject.OnNext(GraphQLWebsocketConnectionState.Connected); Debug.WriteLine($"connection established on websocket {_clientWebSocket.GetHashCode()}, invoking Options.OnWebsocketConnected()"); @@ -491,14 +497,16 @@ private async Task ConnectAsync(CancellationToken token) // send connection init Debug.WriteLine($"sending connection init message"); - await SendWebSocketMessageAsync(initRequest).ConfigureAwait(false); + await SendWebSocketMessageAsync(initRequest, CancellationToken.None).ConfigureAwait(false); var response = await ackTask.ConfigureAwait(false); if (response.Type == GraphQLWebSocketMessageType.GQL_CONNECTION_ACK) + { Debug.WriteLine($"connection acknowledged: {Encoding.UTF8.GetString(response.MessageBytes)}"); + } else { - var errorPayload = Encoding.UTF8.GetString(response.MessageBytes); + string errorPayload = Encoding.UTF8.GetString(response.MessageBytes); Debug.WriteLine($"connection error received: {errorPayload}"); throw new GraphQLWebsocketConnectionException(errorPayload); } @@ -542,15 +550,15 @@ private IObservable GetMessageStream() => }; // add some debug output - var hashCode = subscription.GetHashCode(); + int hashCode = subscription.GetHashCode(); subscription.Add(Disposable.Create(() => Debug.WriteLine($"incoming message subscription {hashCode} disposed"))); Debug.WriteLine($"new incoming message subscription {hashCode} created"); return subscription; }); - private Task _receiveAsyncTask = null; - private readonly object _receiveTaskLocker = new object(); + private Task _receiveAsyncTask; + private readonly object _receiveTaskLocker = new(); /// /// wrapper method to pick up the existing request task if already running /// @@ -563,7 +571,9 @@ private Task GetReceiveTask() if (_receiveAsyncTask == null || _receiveAsyncTask.IsFaulted || _receiveAsyncTask.IsCompleted) + { _receiveAsyncTask = ReceiveWebsocketMessagesAsync(); + } } return _receiveAsyncTask; @@ -579,7 +589,7 @@ private async Task ReceiveWebsocketMessagesAsync() try { - Debug.WriteLine($"waiting for data on websocket {_clientWebSocket.GetHashCode()} (thread {Thread.CurrentThread.ManagedThreadId})..."); + Debug.WriteLine($"waiting for data on websocket {_clientWebSocket.GetHashCode()} (thread {Environment.CurrentManagedThreadId})..."); using var ms = new MemoryStream(); WebSocketReceiveResult webSocketReceiveResult = null; @@ -599,7 +609,7 @@ private async Task ReceiveWebsocketMessagesAsync() case WebSocketMessageType.Text: var response = await _client.JsonSerializer.DeserializeToWebsocketResponseWrapperAsync(ms).ConfigureAwait(false); response.MessageBytes = ms.ToArray(); - Debug.WriteLine($"{response.MessageBytes.Length} bytes received for id {response.Id} on websocket {_clientWebSocket.GetHashCode()} (thread {Thread.CurrentThread.ManagedThreadId})..."); + Debug.WriteLine($"{response.MessageBytes.Length} bytes received for id {response.Id} on websocket {_clientWebSocket.GetHashCode()} (thread {Environment.CurrentManagedThreadId})..."); return response; case WebSocketMessageType.Close: @@ -653,8 +663,7 @@ public void Complete() { lock (_completedLocker) { - if (Completion == null) - Completion = CompleteAsync(); + Completion ??= CompleteAsync(); } } @@ -664,7 +673,7 @@ public void Complete() /// Async disposal as recommended by Stephen Cleary (https://blog.stephencleary.com/2013/03/async-oop-6-disposal.html) public Task? Completion { get; private set; } - private readonly object _completedLocker = new object(); + private readonly object _completedLocker = new(); private async Task CompleteAsync() { Debug.WriteLine("disposing GraphQLHttpWebSocket..."); diff --git a/src/GraphQL.Client/Websocket/GraphQLWebsocketConnectionException.cs b/src/GraphQL.Client/Websocket/GraphQLWebsocketConnectionException.cs index ea4140fb..f9811b98 100644 --- a/src/GraphQL.Client/Websocket/GraphQLWebsocketConnectionException.cs +++ b/src/GraphQL.Client/Websocket/GraphQLWebsocketConnectionException.cs @@ -3,7 +3,7 @@ namespace GraphQL.Client.Http.Websocket; [Serializable] -public class GraphQLWebsocketConnectionException: Exception +public class GraphQLWebsocketConnectionException : Exception { public GraphQLWebsocketConnectionException() { diff --git a/src/GraphQL.Primitives/GraphQLRequest.cs b/src/GraphQL.Primitives/GraphQLRequest.cs index 7d9ee10c..59593d7b 100644 --- a/src/GraphQL.Primitives/GraphQLRequest.cs +++ b/src/GraphQL.Primitives/GraphQLRequest.cs @@ -56,7 +56,7 @@ public GraphQLRequest(string query, object? variables = null, string? operationN Extensions = extensions; } - public GraphQLRequest(GraphQLRequest other): base(other) { } + public GraphQLRequest(GraphQLRequest other) : base(other) { } /// /// Returns a value that indicates whether this instance is equal to a specified object diff --git a/tests/GraphQL.Client.Serializer.Tests/BaseSerializeNoCamelCaseTest.cs b/tests/GraphQL.Client.Serializer.Tests/BaseSerializeNoCamelCaseTest.cs index 9dcabfd7..14d77d16 100644 --- a/tests/GraphQL.Client.Serializer.Tests/BaseSerializeNoCamelCaseTest.cs +++ b/tests/GraphQL.Client.Serializer.Tests/BaseSerializeNoCamelCaseTest.cs @@ -1,4 +1,3 @@ -using System; using System.Text; using FluentAssertions; using GraphQL.Client.Abstractions; diff --git a/tests/GraphQL.Client.Serializer.Tests/BaseSerializerTest.cs b/tests/GraphQL.Client.Serializer.Tests/BaseSerializerTest.cs index 2021a792..ddb71471 100644 --- a/tests/GraphQL.Client.Serializer.Tests/BaseSerializerTest.cs +++ b/tests/GraphQL.Client.Serializer.Tests/BaseSerializerTest.cs @@ -1,10 +1,5 @@ -using System; -using System.IO; -using System.Linq; using System.Reflection; using System.Text; -using System.Threading; -using System.Threading.Tasks; using FluentAssertions; using FluentAssertions.Execution; using GraphQL.Client.Abstractions; diff --git a/tests/GraphQL.Client.Serializer.Tests/ConsistencyTests.cs b/tests/GraphQL.Client.Serializer.Tests/ConsistencyTests.cs index 3bafce7c..200c0acf 100644 --- a/tests/GraphQL.Client.Serializer.Tests/ConsistencyTests.cs +++ b/tests/GraphQL.Client.Serializer.Tests/ConsistencyTests.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using FluentAssertions; using FluentAssertions.Execution; using GraphQL.Client.Serializer.Newtonsoft; @@ -29,7 +28,7 @@ public void MapConvertersShouldBehaveConsistent() {""number"": 567.8} ] }"; - + var newtonsoftSerializer = new NewtonsoftJsonSerializer(); var systemTextJsonSerializer = new SystemTextJsonSerializer(); @@ -37,7 +36,7 @@ public void MapConvertersShouldBehaveConsistent() var systemTextJsonMap = System.Text.Json.JsonSerializer.Deserialize(json, systemTextJsonSerializer.Options); - using(new AssertionScope()) + using (new AssertionScope()) { CompareMaps(newtonsoftMap, systemTextJsonMap); } @@ -52,7 +51,7 @@ private void CompareMaps(Dictionary first, Dictionary map) + if (keyValuePair.Value is Dictionary map) CompareMaps(map, (Dictionary)second[keyValuePair.Key]); else keyValuePair.Value.Should().BeEquivalentTo(second[keyValuePair.Key]); diff --git a/tests/GraphQL.Client.Serializer.Tests/SystemTextJsonSerializerTests.cs b/tests/GraphQL.Client.Serializer.Tests/SystemTextJsonSerializerTests.cs index 38ebc2a1..c94eed8a 100644 --- a/tests/GraphQL.Client.Serializer.Tests/SystemTextJsonSerializerTests.cs +++ b/tests/GraphQL.Client.Serializer.Tests/SystemTextJsonSerializerTests.cs @@ -19,7 +19,7 @@ public class SystemTextJsonSerializeNoCamelCaseTest : BaseSerializeNoCamelCaseTe { public SystemTextJsonSerializeNoCamelCaseTest() : base( - new SystemTextJsonSerializer(new JsonSerializerOptions { Converters = { new JsonStringEnumConverter(new ConstantCaseJsonNamingPolicy(), false)}}.SetupImmutableConverter()), + new SystemTextJsonSerializer(new JsonSerializerOptions { Converters = { new JsonStringEnumConverter(new ConstantCaseJsonNamingPolicy(), false) } }.SetupImmutableConverter()), new GraphQL.SystemTextJson.GraphQLSerializer(new ErrorInfoProvider(opt => opt.ExposeData = true))) { } diff --git a/tests/GraphQL.Client.Serializer.Tests/TestData/DeserializeResponseTestData.cs b/tests/GraphQL.Client.Serializer.Tests/TestData/DeserializeResponseTestData.cs index 6b388483..53388f1f 100644 --- a/tests/GraphQL.Client.Serializer.Tests/TestData/DeserializeResponseTestData.cs +++ b/tests/GraphQL.Client.Serializer.Tests/TestData/DeserializeResponseTestData.cs @@ -1,5 +1,4 @@ using System.Collections; -using System.Collections.Generic; namespace GraphQL.Client.Serializer.Tests.TestData; @@ -119,7 +118,7 @@ public IEnumerator GetEnumerator() IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); private GraphQLResponse NewAnonymouslyTypedGraphQLResponse(T data, GraphQLError[]? errors = null, Map? extensions = null) - => new GraphQLResponse {Data = data, Errors = errors, Extensions = extensions}; + => new GraphQLResponse { Data = data, Errors = errors, Extensions = extensions }; } public class Friend diff --git a/tests/GraphQL.Client.Serializer.Tests/TestData/SerializeToBytesTestData.cs b/tests/GraphQL.Client.Serializer.Tests/TestData/SerializeToBytesTestData.cs index 977ea5af..85725616 100644 --- a/tests/GraphQL.Client.Serializer.Tests/TestData/SerializeToBytesTestData.cs +++ b/tests/GraphQL.Client.Serializer.Tests/TestData/SerializeToBytesTestData.cs @@ -1,5 +1,4 @@ using System.Collections; -using System.Collections.Generic; using GraphQL.Client.Abstractions.Websocket; namespace GraphQL.Client.Serializer.Tests.TestData; diff --git a/tests/GraphQL.Client.Serializer.Tests/TestData/SerializeToStringTestData.cs b/tests/GraphQL.Client.Serializer.Tests/TestData/SerializeToStringTestData.cs index 395b9efc..e01c6335 100644 --- a/tests/GraphQL.Client.Serializer.Tests/TestData/SerializeToStringTestData.cs +++ b/tests/GraphQL.Client.Serializer.Tests/TestData/SerializeToStringTestData.cs @@ -1,7 +1,4 @@ -using System; using System.Collections; -using System.Collections.Generic; -using System.Linq; namespace GraphQL.Client.Serializer.Tests.TestData; diff --git a/tests/GraphQL.Client.Tests.Common/Helpers/CallbackMonitor.cs b/tests/GraphQL.Client.Tests.Common/Helpers/CallbackMonitor.cs index eaf2e10c..b6399a2f 100644 --- a/tests/GraphQL.Client.Tests.Common/Helpers/CallbackMonitor.cs +++ b/tests/GraphQL.Client.Tests.Common/Helpers/CallbackMonitor.cs @@ -44,7 +44,7 @@ public void Reset() public class CallbackAssertions : ReferenceTypeAssertions, CallbackAssertions> { - public CallbackAssertions(CallbackMonitor tester): base(tester) + public CallbackAssertions(CallbackMonitor tester) : base(tester) { } protected override string Identifier => "callback"; diff --git a/tests/GraphQL.Client.Tests.Common/Helpers/ConcurrentTaskWrapper.cs b/tests/GraphQL.Client.Tests.Common/Helpers/ConcurrentTaskWrapper.cs index c49849ed..fa78d4a7 100644 --- a/tests/GraphQL.Client.Tests.Common/Helpers/ConcurrentTaskWrapper.cs +++ b/tests/GraphQL.Client.Tests.Common/Helpers/ConcurrentTaskWrapper.cs @@ -2,10 +2,10 @@ namespace GraphQL.Client.Tests.Common.Helpers; public class ConcurrentTaskWrapper { - public static ConcurrentTaskWrapper New(Func> createTask) => new ConcurrentTaskWrapper(createTask); + public static ConcurrentTaskWrapper New(Func> createTask) => new(createTask); private readonly Func _createTask; - private Task _internalTask = null; + private Task _internalTask; public ConcurrentTaskWrapper(Func createTask) { @@ -24,7 +24,7 @@ public Task Invoke() public class ConcurrentTaskWrapper { private readonly Func> _createTask; - private Task _internalTask = null; + private Task _internalTask; public ConcurrentTaskWrapper(Func> createTask) { @@ -39,11 +39,7 @@ public Task Invoke() return _internalTask = _createTask(); } - public void Start() - { - if (_internalTask == null) - _internalTask = _createTask(); - } + public void Start() => _internalTask ??= _createTask(); public Func> Invoking() => Invoke; diff --git a/tests/GraphQL.Integration.Tests/UriExtensionTests.cs b/tests/GraphQL.Integration.Tests/UriExtensionTests.cs index d218b5d8..7e374578 100644 --- a/tests/GraphQL.Integration.Tests/UriExtensionTests.cs +++ b/tests/GraphQL.Integration.Tests/UriExtensionTests.cs @@ -1,4 +1,4 @@ -using FluentAssertions; +using FluentAssertions; using GraphQL.Client.Http; using Xunit; diff --git a/tests/GraphQL.Integration.Tests/WebsocketTests/Base.cs b/tests/GraphQL.Integration.Tests/WebsocketTests/Base.cs index 35938f34..8978bc35 100644 --- a/tests/GraphQL.Integration.Tests/WebsocketTests/Base.cs +++ b/tests/GraphQL.Integration.Tests/WebsocketTests/Base.cs @@ -29,7 +29,7 @@ protected Base(ITestOutputHelper output, IntegrationServerTestFixture fixture) Fixture = fixture; } - protected static ReceivedMessage InitialMessage = new ReceivedMessage + protected static ReceivedMessage InitialMessage = new() { Content = "initial message", SentAt = DateTime.Now, @@ -42,11 +42,8 @@ public async Task InitializeAsync() // make sure the buffer always contains the same message Fixture.Server.Services.GetService().AddMessage(InitialMessage); - if (ChatClient == null) - { - // then create the chat client - ChatClient = Fixture.GetChatClient(true); - } + // then create the chat client + ChatClient ??= Fixture.GetChatClient(true); } public Task DisposeAsync() @@ -75,7 +72,7 @@ public async void CanUseWebSocketScheme() response.Errors.Should().BeNullOrEmpty(); response.Data.AddMessage.Content.Should().Be(message); } - + [Fact] public async void CanUseDedicatedWebSocketEndpoint() { @@ -88,7 +85,7 @@ public async void CanUseDedicatedWebSocketEndpoint() response.Errors.Should().BeNullOrEmpty(); response.Data.AddMessage.Content.Should().Be(message); } - + [Fact] public async void CanUseDedicatedWebSocketEndpointWithoutHttpEndpoint() { @@ -155,8 +152,7 @@ public async void CanHandleRequestErrorViaWebsocket() } }"; - private readonly GraphQLRequest _subscriptionRequest = new GraphQLRequest(SUBSCRIPTION_QUERY); - + private readonly GraphQLRequest _subscriptionRequest = new(SUBSCRIPTION_QUERY); [Fact] public async void CanCreateObservableSubscription() @@ -234,9 +230,9 @@ public async void CanReconnectWithSameObservable() Debug.WriteLine("disposing subscription..."); observer.Dispose(); // does not close the websocket connection - Debug.WriteLine($"creating new subscription from thread {Thread.CurrentThread.ManagedThreadId} ..."); + Debug.WriteLine($"creating new subscription from thread {Environment.CurrentManagedThreadId} ..."); var observer2 = observable.Observe(); - Debug.WriteLine($"waiting for payload on {Thread.CurrentThread.ManagedThreadId} ..."); + Debug.WriteLine($"waiting for payload on {Environment.CurrentManagedThreadId} ..."); await observer2.Should().PushAsync(1); observer2.RecordedMessages.Last().Data.MessageAdded.Content.Should().Be(message2); @@ -273,12 +269,12 @@ public class UserJoinedContent } - private readonly GraphQLRequest _subscriptionRequest2 = new GraphQLRequest(SUBSCRIPTION_QUERY2); + private readonly GraphQLRequest _subscriptionRequest2 = new(SUBSCRIPTION_QUERY2); [Fact] public async void CanConnectTwoSubscriptionsSimultaneously() { - var port = NetworkHelpers.GetFreeTcpPortNumber(); + int port = NetworkHelpers.GetFreeTcpPortNumber(); var callbackTester = new CallbackMonitor(); var callbackTester2 = new CallbackMonitor(); @@ -376,7 +372,7 @@ public async void CanHandleConnectionTimeout() { websocketStates.Should().ContainSingle(state => state == GraphQLWebsocketConnectionState.Disconnected); - Debug.WriteLine($"Test method thread id: {Thread.CurrentThread.ManagedThreadId}"); + Debug.WriteLine($"Test method thread id: {Environment.CurrentManagedThreadId}"); Debug.WriteLine("creating subscription stream"); var observable = ChatClient.CreateSubscriptionStream(_subscriptionRequest, errorMonitor.Invoke); diff --git a/tests/GraphQL.Primitives.Tests/JsonSerializationTests.cs b/tests/GraphQL.Primitives.Tests/JsonSerializationTests.cs index 2fb2bbc0..14917d58 100644 --- a/tests/GraphQL.Primitives.Tests/JsonSerializationTests.cs +++ b/tests/GraphQL.Primitives.Tests/JsonSerializationTests.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using System.Text.Json; using FluentAssertions; using Xunit; diff --git a/tests/GraphQL.Server.Test/Startup.cs b/tests/GraphQL.Server.Test/Startup.cs index 4dd737c5..114ce5ff 100644 --- a/tests/GraphQL.Server.Test/Startup.cs +++ b/tests/GraphQL.Server.Test/Startup.cs @@ -1,6 +1,4 @@ -using GraphQL.MicrosoftDI; using GraphQL.Server.Test.GraphQL; -using GraphQL.Server.Ui.GraphiQL; namespace GraphQL.Server.Test; diff --git a/tests/IntegrationTestServer/Startup.cs b/tests/IntegrationTestServer/Startup.cs index 65ba8a99..d2b8d427 100644 --- a/tests/IntegrationTestServer/Startup.cs +++ b/tests/IntegrationTestServer/Startup.cs @@ -2,12 +2,8 @@ using GraphQL.Client.Tests.Common; using GraphQL.Client.Tests.Common.Chat.Schema; using GraphQL.Client.Tests.Common.StarWars; -using GraphQL.MicrosoftDI; -using GraphQL.Server; using GraphQL.Server.Ui.Altair; using GraphQL.Server.Ui.GraphiQL; -using GraphQL.SystemTextJson; -using GraphQL.Types; using Microsoft.AspNetCore.Server.Kestrel.Core; namespace IntegrationTestServer; @@ -38,7 +34,7 @@ public void ConfigureServices(IServiceCollection services) { var logger = ctx.Context.RequestServices.GetRequiredService>(); logger.LogError("{Error} occurred", ctx.OriginalException.Message); - return System.Threading.Tasks.Task.CompletedTask; + return Task.CompletedTask; }) .AddErrorInfoProvider(opt => opt.ExposeExceptionDetails = Environment.IsDevelopment()) .AddSystemTextJson() @@ -52,18 +48,12 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseDeveloperExceptionPage(); } - app.UseWebSockets(); - ConfigureGraphQLSchema(app, Common.CHAT_ENDPOINT); - ConfigureGraphQLSchema(app, Common.STAR_WARS_ENDPOINT); + app.UseGraphQL(Common.CHAT_ENDPOINT); + app.UseGraphQL(Common.STAR_WARS_ENDPOINT); app.UseGraphQLGraphiQL(options: new GraphiQLOptions { GraphQLEndPoint = Common.STAR_WARS_ENDPOINT }); app.UseGraphQLAltair(options: new AltairOptions { GraphQLEndPoint = Common.CHAT_ENDPOINT }); } - - private void ConfigureGraphQLSchema(IApplicationBuilder app, string endpoint) where TSchema : Schema - { - app.UseGraphQL(endpoint); - } }