Skip to content

GraphQL.Client: add Websocket support for Blazor WebAssembly host #262

Closed
@bjorg

Description

@bjorg

I would like to help address this issue as I'm a big fan of Blazor WebAssembly and a strong believer in GraphQL as the best API tech. So, supporting GraphQL.Client is of paramount interest. If there is already an effort underway to achieve this, please close this issue as a duplicate and point me in the right direction.

Problem

I've started looking at the code to better understand where the problem is originating from. At the core of the problem are the limited capabilities of the Blazor WASM runtime. For instance, it's not possible to create threads or even block on a thread with Task.Wait() or Task.Result. All operations must be asynchronous as there is only one main thread in the browser execution environment.

The implementation of the GraphQL.Client.Http.Websocket.GraphQLHttpWebSocket class uses System.Reactive.Concurency.EventLoopScheduler, which creates a thread internally. This causes the System.NotSupportedException: Cannot start threads on this runtime. error when the websocket connection is opened.

Solution

There are 2 approaches to potentially address this problem:

Approach 1 - Blazor WASM-friendly System.Reactive.Concurrency.IScheduler implementation

Implement a Blazor WASM-friendly version of System.Reactive.Concurrency.IScheduler that does not require background threads. It would only work reliably when scheduled operations are asynchronous. However, it would be the least invasive change.

Benefits

  • Least invasive
  • Least amount of new code
  • Requires small initialization change in GraphQLHttpWebSocket that could be controlled via a GraphQLHttpClientOptions property to allow current and new implementations to exist side-by-side

Drawback

  • No compile-time detection if the asynchronous requirement is not honored

Approach 2 - Replace System.Reactive in favor of a pure asynchronous implementation

Benefits

  • Removes dependency on System.Reactive (less is better)
  • Clean asynchronous interface enables compiler to assist with async/await code pattern enforcement.
  • Doesn't require to understand how System.Reactive works by deferring continuations to Task-related methods

Drawbacks

  • Breaking change if public interface of GraphQL.Client exposes IObservable
  • Lots of code changes
  • Even more complexity if old and new implementations need to exists side-by-side

Additional

As follow up to this issue, there should also be a sample Blazor WASM application to showcase and test the proper behavior.

Related

The following issues are related:

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions