SignalR - Javascript Hub Proxies

2019-06-12 16:24发布

问题:

When you use SignalR, in your HTML you need to reference the following two scripts:

<script src="~/Scripts/jquery.signalR-1.0.0.js"></script>
<script src="/signalR/hubs"></script>

The second one is for a JavaScript hub proxy which will be auto generated. Everything works fine. However what happens if the JavaScript Hub Proxy generation is disabled somehow, perhaps by setting DisableJavaScriptProxies property (https://github.com/SignalR/SignalR/commit/7e974f4e92551a26f3e3e0a166e1dbf6c064e850). When JavaScript proxy generation is disabled and you try to reference /signalr/hubs in your HTML, it gives the JavaScript error:

Uncaught Error: SignalR: JavaScript Hub proxy generation has been disabled.

When I browse to that path in the browser, the response is:

throw new Error('SignalR: JavaScript Hub proxy generation has been disabled.')

If the JavaScript proxy generation is disabled, how is the $.connection.myHub.client JavaScript code going to work? What extra do I have to do to make it work? The JavaScript error I get is

Uncaught TypeError: cannot read property 'client' of undefined.

回答1:

You can create the proxies yourself. See here.

This is also done in the samples project within the SignalR source. See the MouseTracking example. JS for it (from here):

/// <reference path="../../Scripts/jquery-1.8.2.js" />
/// <reference path="../../Scripts/jquery.signalR.js" />

$(function () {
    var hubConnection = $.hubConnection('/signalr', { qs: 'test=1', logging: false, useDefaultPath: false }),
        hub = hubConnection.createHubProxy('mouseTracking');

    hub.on('move', updateCursor);

    function updateCursor(id, x, y) {
        var e = document.getElementById(id);
        if (!e) {
            e = $('<div id="' + id + '"><i class="icon-screenshot"></i>' + id + '</div>').appendTo(document.body);
            e.css('position', 'absolute');
        }
        else {
            e = $(e);
        }
        e.css({ left: x + 15, top: y + 15 });
    }

    hubConnection.logging = true;
    hubConnection.start({ transport: activeTransport })
        .pipe(function () {
            return hub.invoke('join');
        })
        .pipe(function () {
            $(document).mousemove(function (e) {
                hub.invoke('move', e.pageX, e.pageY);
                updateCursor(hub.state.id, e.pageX, e.pageY);
            });
        });
});


回答2:

You may have disabled it in your Startup class, like so:

public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            ConfigureAuth(app);

            var hubConfiguration = new HubConfiguration();
            hubConfiguration.EnableDetailedErrors = true;
            hubConfiguration.EnableJavaScriptProxies = false;
            app.MapSignalR("/signalr", hubConfiguration);
        }
    }

I had the code above. Removing/commenting out this line: hubConfiguration.EnableJavaScriptProxies = false; should give you proxy generation.

public partial class Startup
        {
            public void Configuration(IAppBuilder app)
            {
                ConfigureAuth(app);

                var hubConfiguration = new HubConfiguration();
                hubConfiguration.EnableDetailedErrors = true;
                app.MapSignalR("/signalr", hubConfiguration);
            }
        }


回答3:

For everybody who stumbles on this issue. It seems to be by design, and even the SignalR utility generates only server proxy methods.

It will not create client methods, even if you have a strongly typed Hub (Client interface).

So, the only correct answer, should be that you should generate small functions, as documented at Microsoft.

As in the stockticker sample:

 $.connection.hub.start()
        .then(init)
        .then(function () {
            return ticker.server.getMarketState();
        })
        .done(function (state) {
            if (state === 'Open') {
                ticker.client.marketOpened();
            } else {
                ticker.client.marketClosed();
            }

The stockticker itself is defined like this public class StockTickerHub : Hub

and the interface

 public interface IClientStock
    {
        void MarketOpened();
        void MarketClosed();
        void MarketReset();
        void UpdateStockPrice(Stock stock);
    }

So for each client proxy method, repeat this. This should not break any bodies project targets.

$.extend(ticker.client, {
        updateStockPrice: function (stock) {
            var displayStock = formatStock(stock),
                $row = $(rowTemplate.supplant(displayStock)),
                $li = $(liTemplate.supplant(displayStock)),
                bg = stock.LastChange < 0
                        ? '255,148,148' // red
                        : '154,240,117'; // green

            $stockTableBody.find('tr[data-symbol=' + stock.Symbol + ']')
                .replaceWith($row);
            $stockTickerUl.find('li[data-symbol=' + stock.Symbol + ']')
                .replaceWith($li);

            $row.flash(bg, 1000);
            $li.flash(bg, 1000);
        },

        marketOpened: function () {
            $("#open").prop("disabled", true);
            $("#close").prop("disabled", false);
            $("#reset").prop("disabled", true);
            scrollTicker();
        },