using Microsoft.AspNetCore.SignalR.Client; namespace ClientApiPoC.Shared.SignalR { public class TunnelClient : NotifyPropertyChangedBase, IDisposable, IAsyncDisposable { #region IDisposable-Implementierung private bool _disposed; protected virtual void Dispose(bool disposing) { if (!_disposed) { if (disposing) { _ = this.DisposeAsync(); } _disposed = true; } } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } public async ValueTask DisposeAsync() { await DisconnectAsync(); } #endregion private HubConnection? _connection = null; public bool IsConnected => (this.ConnectionState == HubConnectionState.Connected); public bool IsConnecting => (this.ConnectionState == HubConnectionState.Connecting || this.ConnectionState == HubConnectionState.Reconnecting); protected HubConnectionState ConnectionState => (_connection?.State ?? HubConnectionState.Disconnected); public async Task ConnectAsync(string url, Action configureConnection) { try { if (string.IsNullOrWhiteSpace(url)) throw new ArgumentNullException(nameof(url)); if (this.IsConnected) throw new InvalidOperationException("SignalR connection is already established."); _connection = new HubConnectionBuilder().WithUrl(url).WithAutomaticReconnect().Build(); _connection.Reconnecting += Connection_Reconnecting; _connection.Reconnected += Connection_Reconnected; _connection.Closed += Connection_Closed; configureConnection(_connection); await _connection.StartAsync(); } finally { await UpdateStateAsync(); } } public async Task DisconnectAsync() { try { if (_connection == null) return; try { if (this.IsConnected) await _connection.StopAsync(); } catch { } _connection.Reconnecting -= Connection_Reconnecting; _connection.Reconnected -= Connection_Reconnected; _connection.Closed -= Connection_Closed; await _connection.DisposeAsync(); _connection = null; } finally { await UpdateStateAsync(); } } private async Task Connection_Reconnecting(Exception? arg) { await UpdateStateAsync(); } private async Task Connection_Reconnected(string? arg) { await UpdateStateAsync(); } private async Task Connection_Closed(Exception? arg) { await UpdateStateAsync(); } private async Task UpdateStateAsync() { OnPropertyChanged(nameof(IsConnected)); OnPropertyChanged(nameof(IsConnecting)); await Task.CompletedTask; } } }