2014-09-11 62 views
4

我使用SignalR为我的应用程序,它与简单的JavaScript工作,但现在我试图重写它与角包装https://github.com/JustMaier/angular-signalr-hub,但我遇到了错误,同时试图连接到我的集线器:SignalR和AngularJS

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; 
}]) 

有谁与熟吗?

+0

以及错误信息SA ys叫'开始'。你尝试过吗? – 2014-09-11 12:31:42

+0

此包装(角服务)的想法https://github.com/JustMaier/angular-signalr-hub,正如我undersand,是控制集线器起始和毂听众和在客户端方法简化declaretion。 – 2014-09-11 12:36:41

+0

这不是ralated到signalr但为什么你使用jQuery模式,尝试使用angularJS指令做这件事http://angular-ui.github.io/bootstrap/ – 2014-09-11 13:38:25

回答

0

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

该库还提供了访问start()的承诺。附上自己的承诺,检查集线器是否已成功连接到服务器。示例:

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

承诺对象是对信号启动方法的承诺的访问。

3

您必须遇到异步问题。当您调用方法时,连接尚未打开。

尝试修复您的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的承诺。因此,角度意识到事件,我们不需要在回调中使用$rootScope.$apply()

和:

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

这是讨论 [here]

vmlf01的评论是:

创建轮毂具有对应于返回值从”。开始了 “.promise” 属性( )”。我使用初始化一个承诺,在完成的()回调解析它在我的连接时建立连接,就像这样:

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; 
    } 
+0

这就像我在答复中指出了同样的问题。只是解决方案不同。 – 2014-10-20 13:00:36

0

确保安装和参考jquery.signalR-2.1.2。js文件

0

包装SignalR时AngularJS使用的是这是什么帮助我:

** 转换所有SignalR(jQuery的)承诺角$ Q承诺。 **

好处:

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

  2. 承诺是在错误(无需try ... catch拒绝),例如如果连接未启动,按您的问题

  3. 角的$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 
};