diff --git a/root.props b/root.props index b32dba6a..61db8f41 100644 --- a/root.props +++ b/root.props @@ -17,7 +17,7 @@ git https://github.com/graphql-dotnet/graphql-client.git True - 2.0.0-alpha.4.subscription-api.7 + 2.0.0-alpha.4.subscription-api.8 4 diff --git a/src/GraphQL.Client/Http/GraphQLHttpClient.cs b/src/GraphQL.Client/Http/GraphQLHttpClient.cs index e6a76359..d242569b 100644 --- a/src/GraphQL.Client/Http/GraphQLHttpClient.cs +++ b/src/GraphQL.Client/Http/GraphQLHttpClient.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Net.Http; using System.Net.Http.Headers; @@ -171,7 +172,7 @@ public IObservable CreateSubscriptionStream(GraphQLRequest requ var observable = graphQlHttpWebSocket.CreateSubscriptionStream(request, Options, cancellationToken: _cancellationTokenSource.Token); - subscriptionStreams.Add(request, observable); + subscriptionStreams.TryAdd(request, observable); return observable; } @@ -202,11 +203,11 @@ public IObservable CreateSubscriptionStream(GraphQLRequest requ return subscriptionStreams[request]; var observable = graphQlHttpWebSocket.CreateSubscriptionStream(request, Options, exceptionHandler, _cancellationTokenSource.Token); - subscriptionStreams.Add(request, observable); + subscriptionStreams.TryAdd(request, observable); return observable; } - private Dictionary> subscriptionStreams = new Dictionary>(); + private ConcurrentDictionary> subscriptionStreams = new ConcurrentDictionary>(); /// /// Releases unmanaged resources diff --git a/src/GraphQL.Client/Http/GraphQLHttpWebSocket.cs b/src/GraphQL.Client/Http/GraphQLHttpWebSocket.cs index 90caf737..28ae1e7b 100644 --- a/src/GraphQL.Client/Http/GraphQLHttpWebSocket.cs +++ b/src/GraphQL.Client/Http/GraphQLHttpWebSocket.cs @@ -81,6 +81,8 @@ await this.clientWebSocket.SendAsync( public Task InitializeWebSocketTask { get; private set; } = Task.CompletedTask; + private object _initializeLock = new object(); + #region Private Methods private Task _backOff() @@ -100,36 +102,39 @@ public Task InitializeWebSocket() if(_disposed != null) throw new OperationCanceledException(); - // if an initialization task is already running, return that - 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) - return Task.CompletedTask; - - // else (re-)create websocket and connect - //_responseStreamConnection?.Dispose(); - clientWebSocket?.Dispose(); - - // fix websocket not supported on win 7 using - // https://github.com/PingmanTools/System.Net.WebSockets.Client.Managed - clientWebSocket = SystemClientWebSocket.CreateClientWebSocket(); - switch (clientWebSocket) + lock (_initializeLock) { - case ClientWebSocket nativeWebSocket: - nativeWebSocket.Options.AddSubProtocol("graphql-ws"); - break; - case System.Net.WebSockets.Managed.ClientWebSocket managedWebSocket: - managedWebSocket.Options.AddSubProtocol("graphql-ws"); - break; - default: - throw new NotSupportedException($"unknown websocket type {clientWebSocket.GetType().Name}"); - } + // if an initialization task is already running, return that + 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) + return Task.CompletedTask; + + // else (re-)create websocket and connect + //_responseStreamConnection?.Dispose(); + clientWebSocket?.Dispose(); + + // 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"); + break; + case System.Net.WebSockets.Managed.ClientWebSocket managedWebSocket: + managedWebSocket.Options.AddSubProtocol("graphql-ws"); + break; + default: + throw new NotSupportedException($"unknown websocket type {clientWebSocket.GetType().Name}"); + } - return InitializeWebSocketTask = _connectAsync(_cancellationTokenSource.Token); + return InitializeWebSocketTask = _connectAsync(_cancellationTokenSource.Token); + } } private IObservable _createResponseStream()