using Microsoft.AspNetCore.SignalR.Client; namespace Connected.Net.Server { public abstract class ServerConnection : IDisposable, IAsyncDisposable, IServerConnection { private HubConnection? _connection; protected ServerConnection(IEndpointServer server) { if (server is null) throw new ArgumentException(null, nameof(server)); Server = server; } public virtual async Task Initialize(string hubUrl) { if (_connection is not null) { if (_connection.State != HubConnectionState.Disconnected) await _connection.StopAsync(); await _connection.DisposeAsync(); } _connection = new HubConnectionBuilder() .WithUrl($"{Server.ServerUrl}/{hubUrl.Trim('/')}") .WithAutomaticReconnect() .Build(); } private bool IsDisposed { get; set; } protected HubConnection Connection => _connection; protected IEndpointServer Server { get; } public async Task Connect() { if (Connection.State != HubConnectionState.Disconnected) return; await Connection.StartAsync(); } public async Task Disconnect() { if (Connection is null) return; if (Connection.State == HubConnectionState.Disconnected) await Connection.StopAsync(); } public async Task Notify(string method, TArgs args) { // TODO: Buffer message if connection is not opened and send it later. if (Connection.State != HubConnectionState.Connected) return; if (Connection.State == HubConnectionState.Connected) await Connection.SendAsync(method, args); } private void Dispose(bool disposing) { if (!IsDisposed) { if (disposing) { if (_connection is not null) { _connection.DisposeAsync() .GetAwaiter() .GetResult(); _connection = null; } } IsDisposed = true; } } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } public async ValueTask DisposeAsync() { if (_connection is not null) { await _connection.DisposeAsync(); _connection = null; } GC.SuppressFinalize(this); } } }