Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Connect to SignalR Hub after connection start

Let's say i have two or more hubs in my server application. My javascipt client (Angular SPA) initialy needs a connection to the first hub, and needs to subscribe to a method like this:

connection = $.hubConnection(appSettings.serverPath);
firstHubProxy = connection.createHubProxy('firstHub');
firstHubProxy('eventFromFirstHub', function () {
        console.log('Method invokation from FirstHub');
            });
connection.start().done(function (data) {
                console.log("hub started");
            });

Everything is working fine. Now a user of my Angular SPA may decide to put a widget on his page, which needs to subcribe to a method from the second hub:

secondHubProxy = connection.createHubProxy('firstHub');
secondHubProxy('eventFromSecondHub', function () {
        console.log('Method invokation from SecondHub');
            });

The method from the second hub is not working. I guess because it was created after connection.start().

My example is simplified, in my real appplication there will be 20+ hubs to which users may or may not subscribe by adding or removing widgets to their page.

As far as i can tell i have two options:

  1. call connection.stop() and then connection.start(). Now both hub subscriptions are working. This just doesn't feel right, because on all hubs, the OnConnected() event fires, and my application will be starting and stopping all the time.
  2. create hub proxy objects for all possible hubs, subscribe to a dummy method on all possible hubs, so the application can subscibe to hub methods later if desired. This also doesn't feel right, because i need to create 20+ hub proxies, while i may need just a few of those.

Is anybody aware of a pattern which i can use to accomplish this? Or am i missing something very simple here?

like image 260
Jeroen1984 Avatar asked Sep 25 '22 22:09

Jeroen1984


1 Answers

Personally I use #2. I have a hub service that subscribes to all client methods. Any of my other angular components then pull that hub service in and subscribe to its events as needed.

Here it is;

hub.js

(function () {
    'use strict';

    angular
        .module('app')
        .factory('hub', hub);

    hub.$inject = ['$timeout'];

    function hub($timeout) {
        var connection = $.connection.myHubName;

        var service = {
            connect: connect,
            server: connection.server,
            states: { connecting: 0, connected: 1, reconnecting: 2, na: 3, disconnected: 4 },
            state: 4
        };

        service = angular.extend(service, OnNotify());

        activate();

        return service;

        function activate() {
            connection.client.start = function (something) {
                service.notify("start", something);
            }

            connection.client.anotherMethod = function (p) {
                service.notify("anotherMethod", p);
            }

            // etc for all client methods 

            $.connection.hub.stateChanged(function (change) {
                $timeout(function () { service.state = change.newState; });
                if (change.state != service.states.connected) service.notify("disconnected");
                console.log("con:", _.invert(service.states)[change.oldState], ">", _.invert(service.states)[change.newState]);
            });

            connect();
        }

        function connect() {
                $.connection.hub.start({ transport: 'auto' });
        }
    }
})();

OnNotify

var OnNotify = function () {
    var callbacks = {};
    return {
        on: on,
        notify: notify
    };

    function on(name, callback) {
        if (!callbacks[name])
            callbacks[name] = [];
        callbacks[name].push(callback);
    };

    function notify(name, param) {
        angular.forEach(callbacks[name], function (callback) {
            callback(param);
        });
    };
}

Then I can subscribe to things as needed, for example in a controller;

(function () {
    'use strict';

    angular
        .module('app')
        .controller('MyController', MyController);

    MyController.$inject = ['hub'];

    function MyController(hub) {
        /* jshint validthis:true */
        var vm = this;
        vm.something = {};

        hub.on('start', function (something) {
            $timeout(function () {
                console.log(something);
                vm.something = something;
            });
        });
    }
})();
like image 111
Stafford Williams Avatar answered Oct 11 '22 14:10

Stafford Williams