diff --git a/src/GraphQL.Client/GraphQLHttpClient.cs b/src/GraphQL.Client/GraphQLHttpClient.cs index 21485f01..eb8835f5 100644 --- a/src/GraphQL.Client/GraphQLHttpClient.cs +++ b/src/GraphQL.Client/GraphQLHttpClient.cs @@ -65,7 +65,7 @@ public GraphQLHttpClient(GraphQLHttpClientOptions options, IGraphQLWebsocketJson if (!HttpClient.DefaultRequestHeaders.UserAgent.Any()) HttpClient.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue(GetType().Assembly.GetName().Name, GetType().Assembly.GetName().Version.ToString())); - _lazyHttpWebSocket = new Lazy(() => new GraphQLHttpWebSocket(Options.EndPoint.GetWebSocketUri(), this)); + _lazyHttpWebSocket = new Lazy(() => new GraphQLHttpWebSocket(Options.WebSocketEndPoint ?? Options.EndPoint.GetWebSocketUri(), this)); } #endregion diff --git a/src/GraphQL.Client/GraphQLHttpClientOptions.cs b/src/GraphQL.Client/GraphQLHttpClientOptions.cs index 6e2c3a46..c727a661 100644 --- a/src/GraphQL.Client/GraphQLHttpClientOptions.cs +++ b/src/GraphQL.Client/GraphQLHttpClientOptions.cs @@ -12,10 +12,15 @@ namespace GraphQL.Client.Http public class GraphQLHttpClientOptions { /// - /// The GraphQL EndPoint to be used + /// The GraphQL EndPoint to be used for HTTP connections /// public Uri EndPoint { get; set; } + /// + /// The GraphQL EndPoint to be used for WebSocket connection + /// + public Uri WebSocketEndPoint { get; set; } + /// /// The that is going to be used /// @@ -47,6 +52,11 @@ public class GraphQLHttpClientOptions public Func> PreprocessRequest { get; set; } = (request, client) => Task.FromResult(request is GraphQLHttpRequest graphQLHttpRequest ? graphQLHttpRequest : new GraphQLHttpRequest(request)); + /// + /// Subscription request preprocessing function. Can be used i.e. to inject authorization info into a GraphQL subscription request payload. + /// + public Func> PreprocessSubscriptionRequest { get; set; } + /// /// This callback is called after successfully establishing a websocket connection but before any regular request is made. /// diff --git a/src/GraphQL.Client/GraphQLHttpRequest.cs b/src/GraphQL.Client/GraphQLHttpRequest.cs index 00f90d4a..eb3aac14 100644 --- a/src/GraphQL.Client/GraphQLHttpRequest.cs +++ b/src/GraphQL.Client/GraphQLHttpRequest.cs @@ -16,7 +16,7 @@ public GraphQLHttpRequest(string query, object? variables = null, string? operat { } - public GraphQLHttpRequest(GraphQLRequest other): base(other.Query, other.Variables, other.OperationName) + public GraphQLHttpRequest(GraphQLRequest other): base(other) { } diff --git a/src/GraphQL.Client/Websocket/GraphQLHttpWebSocket.cs b/src/GraphQL.Client/Websocket/GraphQLHttpWebSocket.cs index aba35e8f..488db435 100644 --- a/src/GraphQL.Client/Websocket/GraphQLHttpWebSocket.cs +++ b/src/GraphQL.Client/Websocket/GraphQLHttpWebSocket.cs @@ -98,12 +98,11 @@ public IObservable> CreateSubscriptionStream>(async observer => { Debug.WriteLine($"Create observable thread id: {Thread.CurrentThread.ManagedThreadId}"); - await _client.Options.PreprocessRequest(request, _client); var startRequest = new GraphQLWebSocketRequest { Id = Guid.NewGuid().ToString("N"), Type = GraphQLWebSocketMessageType.GQL_START, - Payload = request + Payload = await (_client.Options.PreprocessSubscriptionRequest?.Invoke(request, _client) ?? _client.Options.PreprocessRequest(request, _client)) }; var closeRequest = new GraphQLWebSocketRequest { @@ -136,6 +135,7 @@ public IObservable> CreateSubscriptionStream( response.MessageBytes); + Debug.WriteLine($"payload => {System.Text.Encoding.UTF8.GetString(response.MessageBytes)}"); o.OnNext(typedResponse.Payload); // in case of a GraphQL error, terminate the sequence after the response has been posted @@ -194,10 +194,12 @@ public IObservable> CreateSubscriptionStream> CreateSubscriptionStream> CreateSubscriptionStream { - Debug.WriteLine($"unwrap exception thread id: {Thread.CurrentThread.ManagedThreadId}"); // if the result contains an exception, throw it on the observable if (t.Item2 != null) + { + Debug.WriteLine($"unwrap exception thread id: {Thread.CurrentThread.ManagedThreadId} => {t.Item2}"); return Observable.Throw>(t.Item2); - - return t.Item1 == null - ? Observable.Empty>() - : Observable.Return(t.Item1); + } + if (t.Item1 == null) + { + Debug.WriteLine($"empty item thread id: {Thread.CurrentThread.ManagedThreadId}"); + return Observable.Empty>(); + } + return Observable.Return(t.Item1); }) // transform to hot observable and auto-connect .Publish().RefCount(); @@ -319,7 +325,7 @@ public Task> SendRequest(GraphQLRequest re } catch (Exception e) { - Console.WriteLine(e); + Debug.WriteLine(e); throw; } @@ -408,7 +414,7 @@ public Task InitializeWebSocket() #else _clientWebSocket = new ClientWebSocket(); _clientWebSocket.Options.AddSubProtocol("graphql-ws"); - if(!System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Create("WEBASSEMBLY"))) + if(!System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Create("BROWSER"))) { // the following properties are not supported in Blazor WebAssembly and throw a PlatformNotSupportedException error when accessed _clientWebSocket.Options.ClientCertificates = ((HttpClientHandler)Options.HttpMessageHandler).ClientCertificates; diff --git a/src/GraphQL.Primitives/GraphQLRequest.cs b/src/GraphQL.Primitives/GraphQLRequest.cs index 72033552..19c7fded 100644 --- a/src/GraphQL.Primitives/GraphQLRequest.cs +++ b/src/GraphQL.Primitives/GraphQLRequest.cs @@ -49,6 +49,14 @@ public GraphQLRequest(string query, object? variables = null, string? operationN OperationName = operationName; } + public GraphQLRequest(IEnumerable> values) + { + foreach(var kv in values) + { + Add(kv.Key, kv.Value); + } + } + /// /// Returns a value that indicates whether this instance is equal to a specified object /// @@ -86,7 +94,7 @@ public override int GetHashCode() { unchecked { - var hashCode = Query.GetHashCode(); + var hashCode = Query?.GetHashCode() ?? 0; hashCode = (hashCode * 397) ^ OperationName?.GetHashCode() ?? 0; hashCode = (hashCode * 397) ^ Variables?.GetHashCode() ?? 0; return hashCode;