Search code examples
c#asp.net-coreconnectionsignalr.clientasp.net-core-signalr

SignalR Core - Check connection state from WebAPI


I am using Microsoft.AspNetCore.SignalR.Client to open a connection from my WebAPI project to connect and call methods in my SignalR Hub project. These are separate projects hosted on separate servers.

How do I check whether the connection has been started, so I don't try to start it twice?

I connect from WebAPI using the following code:

public class ChatApi
{
    private readonly HubConnection _connection;

    public ChatApi()
    {
        var connection = new HubConnectionBuilder();
        _connection = connection.WithUrl("https://localhost:44302/chathub").Build();
    }

    public async Task SendMessage(Msg model)
    {
        await _connection.StartAsync();
        await _connection.SendAsync("Send", model);
    }
}

Since my WebAPI will be calling into SignalR quite a bit, I want to create the single connection between WebAPI and SignalR and not close/open the connection each time. At the moment I create the ChatApi class as a singleton and initialize the hub connection in the constructor.

How would I check if the connection is started before calling await _connection.StartAsync();?

Using: Microsoft.AspNetCore.SignalR.Client v1.0.0-preview1-final


Solution

  • Microsoft.AspNetCore.SignalR.Client v1.1.0+

    There is a State property on HubConnection.

    public class ChatApi
    {
        private readonly HubConnection _connection;
    
        public ChatApi()
        {
            _connection = new HubConnectionBuilder()
                .WithUrl("https://localhost:44302/chathub")
                .Build();
        }
    
        public async Task StartIfNeededAsync()
        {
            if (_connection.State == HubConnectionState.Disconnected)
            {
                await _connection.StartAsync();
            }
        }
    
        public async Task SendMessage(Msg model)
        {
            await StartIfNeededAsync();
            await _connection.SendAsync("Send", model);
        }
    }
    

    References:

    Microsoft.AspNetCore.SignalR.Client < v1.1.0

    (At the time of this writing, the latest version was 1.0.0-preview2-final.)

    There is no ConnectionState property.

    You need to track the state yourself, by subscribing to the Closed event on HubConnection.

    public class ChatApi
    {
        private readonly HubConnection _connection;
    
        private ConnectionState _connectionState = ConnectionState.Disconnected;
    
        public ChatApi()
        {
            var connection = new HubConnectionBuilder();
            _connection = connection.WithUrl("https://localhost:44302/chathub").Build();
    
            // Subscribe to event
            _connection.Closed += (ex) =>
            {
                if (ex == null)
                {
                    Trace.WriteLine("Connection terminated");
                    _connectionState = ConnectionState.Disconnected;
                }
                else
                {
                    Trace.WriteLine($"Connection terminated with error: {ex.GetType()}: {ex.Message}");
                    _connectionState = ConnectionState.Faulted;
                }
            };
        }
    
        public async Task StartIfNeededAsync()
        {
            if (_connectionState == ConnectionState.Connected)
            {
                return;
            }
    
            try
            {
                await _connection.StartAsync();
                _connectionState = ConnectionState.Connected;
            }
            catch (Exception ex)
            {
                Trace.WriteLine($"Connection.Start Failed: {ex.GetType()}: {ex.Message}");
                _connectionState = ConnectionState.Faulted;
                throw;
            }
        }
    
        private enum ConnectionState
        {
            Connected,
            Disconnected,
            Faulted
        }
    }
    

    Usage:

    public async Task SendMessage(Msg model)
    {
        await StartIfNeededAsync();
        await _connection.SendAsync("Send", model);
    }
    

    References: