graphql-client icon indicating copy to clipboard operation
graphql-client copied to clipboard

GraphQL.Client Subscription Error from Xamarin

Open henry-delgado opened this issue 3 years ago • 2 comments

Hi everyone, I have a proof of concept on AppSync/GraphQL.Client. I am successfully querying and creating GraphQL mutations. However, I get an error when trying to subscribe.

Error: Unable to connect to the remote server Stack Trace:

  at System.Net.WebSockets.WebSocketHandle.ParseAndValidateConnectResponseAsync (System.IO.Stream stream, System.Net.WebSockets.ClientWebSocketOptions options, System.String expectedSecWebSocketAccept, System.Threading.CancellationToken cancellationToken) [0x00100] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/external/corefx/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Managed.cs:337 
  at System.Net.WebSockets.WebSocketHandle.ConnectAsyncCore (System.Uri uri, System.Threading.CancellationToken cancellationToken, System.Net.WebSockets.ClientWebSocketOptions options) [0x00383] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/external/corefx/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/WebSocketHandle.Managed.cs:148 
  at System.Net.WebSockets.ClientWebSocket.ConnectAsyncCore (System.Uri uri, System.Threading.CancellationToken cancellationToken) [0x000d1] in /Library/Frameworks/Xamarin.iOS.framework/Versions/Current/src/Xamarin.iOS/external/corefx/src/System.Net.WebSockets.Client/src/System/Net/WebSockets/ClientWebSocket.cs:157 
  at GraphQL.Client.Http.Websocket.GraphQLHttpWebSocket.ConnectAsync (System.Threading.CancellationToken token) [0x000ff] in <5343ffaac4864176b8f7c0b9cc6d172c>:0 

I was reading on AWS App Sync documentation that the web socket URL is different from the GraphQL Endpoint.

I am trying to follow the example from the integration test

Code

        public static void CreateSubscription()
        {
            var subscriptions = new CompositeDisposable();

            subscriptions.Add(Client.WebSocketReceiveErrors.Subscribe(e =>
            {
                if (e is WebSocketException we)
                    Console.WriteLine($"WebSocketException: {we.Message} (WebSocketError {we.WebSocketErrorCode}, ErrorCode {we.ErrorCode}, NativeErrorCode {we.NativeErrorCode}");
                else
                    Console.WriteLine($"Exception in websocket receive stream: {e.ToString()}");
            }));

            subscriptions.Add(CreateSubscription("1"));            

        }

        private static IDisposable CreateSubscription(string id)
        {
            var taskCreatedRequest = new GraphQLRequest
            {
                Query = @"
                subscription {
                    onCreateTasksPocModel{
                        id
                        description
                        date
                    }
                }",
                Variables = new
                {
                    id
                }
            };
            
            IObservable<GraphQLResponse<CreateTasksResponse>> subscriptionStream
                = Client.CreateSubscriptionStream<CreateTasksResponse>(taskCreatedRequest);

            var subscription = subscriptionStream.Subscribe(
                response => {
                    Console.WriteLine($"new message from \"{response}\": {response}");
                    },
                exception => {
                    Console.WriteLine($"message subscription stream failed: {exception}");
                    },
                () =>
                {
                    Console.WriteLine($"message subscription stream completed");
                });
            return subscription;
        }

        static GraphQLHttpClient CreateClient()
        {
            var graphQLOptions = new GraphQLHttpClientOptions()
            {
                EndPoint = new Uri(GraphQLConstants.GraphQLApiUrl), //https://<graphql-URL>
                //AppSync real-time endpoint from the AWS AppSync GraphQL endpoint is different for websocket
                //as per https://docs.aws.amazon.com/appsync/latest/devguide/real-time-websocket-client.html
                WebSocketEndPoint = new Uri(GraphQLConstants.GraphQLSocketUrl),//wss://<graphql-URL>
                HttpMessageHandler = new NativeMessageHandler(),
                UseWebSocketForQueriesAndMutations =true
            };

            var client = new GraphQLHttpClient(graphQLOptions, new NewtonsoftJsonSerializer());
            client.HttpClient.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue(new ProductHeaderValue(nameof(MobileGraphql))));
            client.HttpClient.DefaultRequestHeaders.Add(GraphQLConstants.ApiKeyName, GraphQLConstants.ApiKeyValue);
            client.HttpClient.DefaultRequestHeaders.Host = GraphQLConstants.GraphQLHost;
            return client;
        }

View Full Source Code (Gist

I have read similar issues such #333 but that has not helped and wonder if anyone could help me out.

Thanks

henry-delgado avatar Apr 20 '21 00:04 henry-delgado

If you set UseWebSocketForQueriesAndMutations, it does what it says: It tries to use the websocket for mutations and queries, too.

I don't think that's supported by the AWS AppSync websocket endpoint... so please try to set that to false...

rose-a avatar Apr 21 '21 19:04 rose-a

Hi @rose-a , I have tried that too and still get the same error. I tried both removing that setting and also tried explicitly setting it to false.

I created the subscription at the start of the (mobile) application then I see it failing on the following WebSocketException with the error Unable to connect to the remote server

        public static void CreateSubscription()
        {
            var subscriptions = new CompositeDisposable();

            subscriptions.Add(Client.WebSocketReceiveErrors.Subscribe(e =>
            {
                if (e is WebSocketException we)
                    Console.WriteLine($"WebSocketException: {we.Message} (WebSocketError {we.WebSocketErrorCode}, ErrorCode {we.ErrorCode}, NativeErrorCode {we.NativeErrorCode}");
                else
                    Console.WriteLine($"Exception in websocket receive stream: {e.ToString()}");
            }));

            subscriptions.Add(CreateSubscription("1"));            

        }

henry-delgado avatar Apr 23 '21 13:04 henry-delgado