supabase-community / supabase-csharp

A C# Client library for Supabase
https://github.com/supabase-community/supabase-csharp/wiki
MIT License
501 stars 51 forks source link

.NET 6 - _client.InitializeAsync() gets stuck when AutoConnectRealtime = true #60

Closed BlueWaterCrystal closed 1 year ago

BlueWaterCrystal commented 1 year ago

Hi,

When AutoConnectRealtimeis set to true, GetAuthenticationStateAsyncdoesn't return as await _client.InitializeAsync() gets stuck but still authenticates.

However, when a page refreshes and GetAuthenticationStateAsyncis called, it doesn't get stuck.

When AutoConnectRealtimeis set to false, GetAuthenticationStateAsyncreturns normally when called from AuthService.

I'm presuming when the page is reloaded, it creates the ClaimsIdentity from the data from supabase it got from before and that's how it's currently authenticating instead of fully authenticating when called from AuthService.

rhuanbarros commented 1 year ago

Hello, I don't think this is a bug, because the AutoConnectRealtime is setted to true in the BlazorWebAssemblySupabaseTemplate and it is working fine.

Furthermore, it could be trick to set the authentication to work ok, because there is a lot going on. Maybe if you share a sample project of your implementation with this bug, I could help.

BlueWaterCrystal commented 1 year ago

Hi,

I meant to add it to Questions.

The code is mostly the same other than being non-webassembly,

I've just tested putting await client.InitializeAsync(); inside the AuthService and it runs correctly, and then GetAuthenticationStateAsync can read the token, though InitializeAsync() would only execute on login

Not sure how GetAuthenticationStateAsync can read the session data but not execute InitializeAsync()

Is there something InitializeAsync() requires that could be missing?

rhuanbarros commented 1 year ago

I would like to retract what I said. I just test it a bit more and find that my code on the template isn't work anymore. It was working when I deploy, but now it really get stucked await client.InitializeAsync();

Since the auth code didn't change in the last commits, I need to verify if it is a problem with the Supabase server or if something change in the last updates of the api.

rhuanbarros commented 1 year ago

I downgraded the supabase-csharp api to the 0.8.3 version and it worked fine. Can you try this version @BlueWaterCrystal ?

My csproj file


<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">

  <PropertyGroup>
    <TargetFramework>net7.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <ServiceWorkerAssetsManifest>service-worker-assets.js</ServiceWorkerAssetsManifest>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="7.0.0" />
    <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="7.0.0" />
    <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="7.0.0" PrivateAssets="all" />

    <PackageReference Include="Blazored.LocalStorage" Version="4.3.0" />

    <PackageReference Include="MudBlazor" Version="6.1.2" />

    <PackageReference Include="gotrue-csharp" Version="3.0.5" />
    <PackageReference Include="postgrest-csharp" Version="3.1.3" />
    <PackageReference Include="supabase-csharp" Version="0.8.3" />
  </ItemGroup>

  <ItemGroup>
    <ServiceWorker Include="wwwroot\service-worker.js" PublishedContent="wwwroot\service-worker.published.js" />
  </ItemGroup>

</Project>
BlueWaterCrystal commented 1 year ago

Hi,

Version 0.8.3 Seems to fix the issue.

It looks like the core issue is related to realtime-csharp, anything above 5.0.1 seems to produce the issue.

BlueWaterCrystal commented 1 year ago

The error occurs in Client.cs

        public Task<IRealtimeClient<RealtimeSocket, RealtimeChannel>> ConnectAsync()
        {
            var tsc = new TaskCompletionSource<IRealtimeClient<RealtimeSocket, RealtimeChannel>>();

            try
            {
                Connect(tsc.SetResult);
            }
            catch (Exception ex)
            {
                tsc.TrySetException(ex);
            }

            return tsc.Task;
        }

It looks like when the socket isn't null, it doesn't send a callback to the ConnectAsync(), invoking the callback seems to fix it. In 5.0.1 I believe method used to use TrySetResult Possible fix:

        public IRealtimeClient<RealtimeSocket, RealtimeChannel> Connect(Action<IRealtimeClient<RealtimeSocket, RealtimeChannel>>? callback = null)
        {

            if (socket != null)
            {
                Options.Logger("error", "Socket already exists.", null);
                callback?.Invoke(this);
                return this;
            }

            EventHandler<SocketStateChangedEventArgs>? cb = null;

            cb = (object sender, SocketStateChangedEventArgs args) =>
            {
                switch (args.State)
                {
                    case SocketStateChangedEventArgs.ConnectionState.Open:
                        socket!.StateChanged -= cb;
                        callback?.Invoke(this);
                        break;
                    case SocketStateChangedEventArgs.ConnectionState.Close:
                    case SocketStateChangedEventArgs.ConnectionState.Error:
                        socket!.StateChanged -= cb;
                        throw new Exception("Error occurred connecting to Socket. Check logs.");
                }
            };

            socket = new RealtimeSocket(realtimeUrl, Options, SerializerSettings);

            socket.StateChanged += HandleSocketStateChanged;
            socket.OnMessage += HandleSocketMessage;
            socket.OnHeartbeat += HandleSocketHeartbeat;

            socket.StateChanged += cb;
            socket.Connect();

            return this;
        }
acupofjose commented 1 year ago

Available in 0.8.7 - Thanks for y'all's help!