Understanding SignalR’s HubConnection from a .Net Client Perspective

cweb-api

I if may point out I don't have a code issue nor the requirement for code review, hence posting here.

I'm generally looking for a better understanding on how to truly architect a SignalR .Net Client project to prevent multiple HubConnections being instantiated.

I/We have a prototype in a staging environment, which successfully passes print information from remote distribution centres to our app.

What truly baffles me is that I am instantiating a HubConnection every time I need to send a message accessed directly on the Hub, not an api endpoint.

Please allow me to demonstrate some code, So our system talks to a locked down api, which then talks to a hub hosted else where.

    [IdentityBasicAuthentication]
    [Authorize]
    [RoutePrefix("api/v1")]
    public class PrinterStatusV1Controller : ApiController
    {
        //logic removed
        private HubConnection _hubConnection;

        public PrinterStatusV1Controller()
        {   
            //logic removed
        }

        [HttpPost]
        [Route("dummy")]
        public async Task<IHttpActionResult> AddPrinterStatusAsync([FromBody]PrinterStatus printerStatus)
        {
            try
            {
                var identity = User.Identity as ClaimsIdentity;

                var identityInstance = new IdentityInstance(identity);
                if (identityInstance == null)
                    return StatusCode(HttpStatusCode.Forbidden);

                if (printerStatus == null)
                    return NotFound();

                IHubProxy aProxy = Create(dummy);

                if(printerProxy != null)
                    await printerProxy.Invoke("dummy", dummy);

                await _printerStatusRepo.Dummy(dummy);
                return Ok();
            }
            catch (System.Exception ex)
            {
                return InternalServerError();
            }
        }
        private IHubProxy Create(string dummy)
        {
            try
            {
                /logic removed
                _hubConnection = new HubConnection("dummy", dictionary);
                var hubProxy = _hubConnection.CreateHubProxy("dummy");
                _hubConnection.Start().Wait();

                _hubConnection.Closed += () => {
                    var connected = false;
                    while (!connected)
                    {
                        System.Threading.Thread.Sleep(2000);
                        _hubConnection = new HubConnection("dummy", dictionary);
                        hubProxy = _hubConnection.CreateHubProxy("dummy");
                        _hubConnection.Start().Wait();
                        connected = true;
                    }
                };

                return hubProxy;
            }
            catch
            {
                return null;
            }
        }
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_hubConnection != null)
                {
                    _hubConnection.Stop();
                    _hubConnection.Dispose();
                }

                //logic removed
            }
            base.Dispose(disposing);
        }
    }
}

I should get to the point, What is the generally the best pattern/architecture to avoid creating a HubConnection, every time I call an endpoint? any hints greatly appreciated. I can put many abstractions in place but theoretically it's going instantiate a new HubConnection each time..

Best Answer

Maintain a reference to one HubConnection object, and re-use it for subsequent API calls.

This can be done in a number of different ways, without overly complicating your architecture. For example, if you're using a DI container, you can tell your container to use a Singleton lifetime, so that when you ask for a HubConnection object, you get the same one back each time.

Instance members of HubConnection are not thread safe. Treat them accordingly.

Related Topic