【问题标题】:SignalR and AngularJSSignalR 和 AngularJS
【发布时间】:2014-11-05 09:39:58
【问题描述】:

我在我的应用程序中使用 SignalR,它适用于简单的 javascript,但现在我尝试使用 angular-wrapper https://github.com/JustMaier/angular-signalr-hub 重写它,但在尝试连接到我的集线器时遇到了错误:

Error: SignalR: Connection must be started before data can be sent. Call .start() before .send()
at Object.signalR.fn.signalR.send (http://localhost:47124/Scripts/jquery.signalR-2.1.1.js:789:23)
at Object.hubProxy.fn.hubProxy.invoke (http://localhost:47124/Scripts/jquery.signalR-2.1.1.js:2609:24)
at Hub.invoke (http://localhost:47124/Scripts/angular-signalr-hub.js:30:28)
at Hub.(anonymous function) [as loadRecentPhotos] (http://localhost:47124/Scripts/angular-signalr-hub.js:49:24)
at Object.PhotoMarkers.load (http://localhost:47124/Scripts/AngApp.js:47:17)
at http://localhost:47124/Scripts/angular.js:10836:21
at Scope.$eval (http://localhost:47124/Scripts/angular.js:12673:28)
at pre (http://localhost:47124/Scripts/angular.js:19943:15)
at nodeLinkFn (http://localhost:47124/Scripts/angular.js:6684:13)
at compositeLinkFn (http://localhost:47124/Scripts/angular.js:6098:13) <div class="modal-body" ng-init="markers.load()"> 

这是我的代码:

angular.module('FlickrMaps', ['SignalR'])
.factory('PhotoMarkers', ['$rootScope', 'Hub', function ($rootScope, Hub) {
    var PhotoMarkers = this;

    //Hub setup
    var hub = new Hub('photos', {
        listeners: {
            'addTotalPhotosCount': function (total) {
                PhotoMarkers.totalCount = total;
                $rootScope.$apply();
            },

            'initPhotoMarker': function (photo) {
                var photolocation = new window.google.maps.LatLng(photo.Latitude, photo.Longitude);
                PhotoMarkers.all.push(new window.google.maps.Marker({
                    position: photolocation,
                    title: photo.Title,
                    photoThumb: photo.PhotoThumbScr,
                    photoOriginal: photo.PhotoOriginalScr
                }));
                $rootScope.$apply();
            },

            'photosProcessed': function () {
                PhotoMarkers.processedPhotosCount++;
                $rootScope.$apply();
            },
        },
        methods: ['loadRecentPhotos'],
        errorHandler: function (error) {
            console.error(error);
        }
    });

    //Variables
    PhotoMarkers.all = [];
    PhotoMarkers.processedPhotosCount = 0;
    PhotoMarkers.totalCount = 0;

    //Methods
    PhotoMarkers.load = function () {
        $('#myModal').modal({
            backdrop: 'static',
            keyboard: false
        });
        hub.loadRecentPhotos();
    };

    return PhotoMarkers;
}])
.controller('MapController', ['$scope', 'PhotoMarkers', function ($scope, PhotoMarkers) {
$scope.markers = PhotoMarkers;
}])

有人知道吗?

【问题讨论】:

  • 好吧,错误消息说要调用start。你试过吗?
  • 据我了解,这个包装器(角度服务)github.com/JustMaier/angular-signalr-hub 的想法是控制集线器启动并简化客户端集线器侦听器和方法的声明。
  • 这与 signalr 无关,但你为什么使用 jquery modal,尝试使用 angularJS 指令来做到这一点angular-ui.github.io/bootstrap
  • 好吧,我是 Angular 新手,只是迈出第一步。不过下次我会用,谢谢!
  • @AlexanderSmith 您是否愿意接受另一个包装器解决方案,我可以发布一个更灵活的自定义包装器,请告诉我!

标签: .net angularjs signalr


【解决方案1】:

您一定遇到了异步问题。调用方法时,连接尚未打开。

尝试修复你的signalr-hub.js,我认为我们应该使用不同的承诺来停止和开始。

    Hub.disconnect = function () {
        Hub.stopPromise = Hub.connection.stop();
    };
    Hub.connect = function () {
        Hub.startPromise = Hub.connection.start();
    };

还有:

angular.forEach(options.methods, function (method) {
        Hub[method] = function () {
            var args = $.makeArray(arguments);
            args.unshift(method);
            return Hub.startPromise.then(function(){
                //invoke method only after startPromise is resolved
                 return Hub.invoke.apply(Hub, args);
            }
        };
});

或者:

angular.forEach(options.methods, function (method) {
        Hub[method] = function () {
            var args = $.makeArray(arguments);
            args.unshift(method);

            var def = $q.def();
            Hub.startPromise.then(function(){
                    //invoke method only after startPromise is resolved
                  Hub.invoke.apply(Hub, args).done(function(){
                         def.resolve();
                  });
            }

            return def.promise;
        };
 });

不要忘记将$q 注入您的集线器。这将返回一个角度承诺而不是 jQuery 承诺。因此,Angular 知道该事件,我们不需要在您的回调中使用$rootScope.$apply()

还有:

//Adding additional property of promise allows to access it in rest of the application.
   Hub.startPromise = Hub.connection.start();

【讨论】:

    【解决方案2】:

    我在 Github 上有一个基本的工作示例。 希望能帮助到你。虽然它确实使用身份验证,但如果这对您不重要。 您可以简单地删除身份验证部分。

    https://github.com/louislewis2/AngularJSAuthentication

    问候

    路易

    【讨论】:

      【解决方案3】:

      根据 SignalR-Hub 项目的源代码,创建新集线器时应启动连接。您是否检查过浏览器控制台是否存在连接错误?

      该库还提供对start() 承诺的访问。将自己附加到此承诺以检查集线器是否已成功连接到您的服务器。示例:

      hub.promise
          .done(function(){ console.log('connection established'); })
          .fail(function(){ console.log('connection error'); });
      

      promise 对象是对signalR start 方法的promise 的访问。

      【讨论】:

        【解决方案4】:

        这是讨论 [here]

        vmlf01 的评论是:

        创建的集线器有一个“.promise”属性,对应于“.start()”的返回值。我使用承诺初始化我的连接,并在建立连接时在 done() 回调中解决它,如下所示:

            function initialize() {
                var deferred = $q.defer();
        
                foldersHubConnection = new Hub('Folders', {
                    listeners: folderHubListeners(),
                    methods: folderServerCalls(),
                    rootPath: config.eventsServerEndpoint
                });
        
                foldersHubConnection.promise.done(function () {
                    deferred.resolve(foldersHubClient);
                });
        
                foldersHubConnection.promise.fail(function (error) {
                    deferred.reject(new Error("Error connecting to Events Server: " + error));
                });
        
                return deferred.promise;
            }
        

        【讨论】:

        • 这与我在回答中指出的问题相同。只是解决方案不同。
        【解决方案5】:

        确保安装并引用 jquery.signalR-2.1.2.js 文件

        【讨论】:

          【解决方案6】:

          在包装 SignalR 以供 AngularJS 使用时,对我有帮助的是:

          ** 将所有 SignalR (jQuery) 承诺转换为 Angular $q 承诺。 **

          好处:

          1. 所有调用者都有一个一致的承诺接口(例如finally()而不是always()

          2. Promise 因错误而被拒绝(不需要try...catch),例如如果连接没有开始,根据你的问题

          3. Angular 的 $digest 循环被触发

          考虑到这一点,您可以将 Hub.invoke 方法更改为:

          Hub.invoke = function(method, args) {
              try {
                 var jQueryPromise = Hub.proxy.invoke.apply(Hub.proxy, arguments);
          
                  return $q.when(jQueryPromise);    // <- return as $q promise
          
              } catch(e) {
                  return $q.reject(e);              // <- exception to $q.reject
              }
          

          Hub.connect

          Hub.connect = function (queryParams) {
              ...
              return $q.when(Hub.connection.start(startOptions));  // <- return $q promise
          };
          

          【讨论】:

            猜你喜欢
            • 2014-02-02
            • 2013-12-02
            • 1970-01-01
            • 2017-04-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-01-02
            • 2017-02-01
            相关资源
            最近更新 更多