SignalR 客户端在 AngularJs 控制器中不起作用

Posted

技术标签:

【中文标题】SignalR 客户端在 AngularJs 控制器中不起作用【英文标题】:SignalR client doesn't work inside AngularJs controller 【发布时间】:2015-08-09 03:58:21 【问题描述】:

我创建了基于路由的 Angular 应用程序。 在不使用路由的情况下,Signalr 可以正常工作,但是当我使用路由时,Signalr 只能以一种方式工作 - 从客户端到服务器。

<html ng-app="SignalR">
<head>
//Scripts
<script src="~/signalr/hubs"></script>
</head>
<body>
<a href="#/Today">Today</a>
<a href="#/History">History</a>

<div ng-view>
</div>

<script type="text/javascript">
    var hubConnetion = undefined;
    hubConnetion = $.connection.hubs;
    $.connection.hub.start();


    var SignalRControllers = angular.module('SignalRControllers', []);

    var SignalRApp = angular.module('SignalR', ['ngRoute', 'SignalRControllers']);


    SignalRApp.config(['$routeProvider',
      function ($routeProvider) 
          $routeProvider.
            when('/Today', 
                templateUrl: '@Url.Action("Today","Home")'
            ).
            when('/History', 
                templateUrl: '@Url.Action("History", "Home")'
            )
      ]);

</script>
<script src="~/AngularJs/TodayController.js"></script>
</body>
</html>

TodayController.js

SignalRControllers.controller('TodayController', ['$scope', '$http',
  function ($scope, $http) 

      $scope.sendTask = function () 
          hubConnetion.server.sendTask($("#taskName").val());//works
      

      $scope.Task = "task1";
      hubConnetion.client.getTask= function (Task) //never invoked
          $scope.Task = Task;
      
  ]);

Today.html

<div ng-controller="TodayController">

    <div>Task</div>


    <input id="taskName" type="text" />
    <div ng-click="sendTask()">SendTask</div>

</div>

Hubs.cs

public class Hubs: Hub

   public void SendTask(string Name)
   
      Clients.All.GetTask(Name);
   

我不确定,但我认为因为 hubConnetion 变量包装在控制器内,signlarR 找不到它。 有没有什么角度魔法可以解决这个问题?

【问题讨论】:

请在 Today.html 中添加所有代码,而不仅仅是控制器.. 没有更多代码了,就这样 【参考方案1】:

您的解决方案是完美的,对于即使在您的讲座之后仍面临此问题的人,有一个简单的解决方案可以在应用程序的每个部分从服务器到客户端获得响应:

    angular.module('groupApp').run(function ($rootScope, chat) 
        $rootScope.messages = [];
        chat.client.newMessage = function onNewMessage(message) 
           $rootScope.messages.push( message: message );
           $rootScope.$apply();
    ;
);

在您看来,您可以在任何地方使用“消息”数组:

 <div ng-repeat="m in messages">
        m.message
 </div>

My issue

【讨论】:

【参考方案2】:

我也是 SignalR 的新手(也是 Angular 的第一次用户),所以我在 ASP.NET MVC 4 (SignalR 2.2) 中重新创建(并简化了)项目以解决问题。而且我认为还有不止一个...

1) SignalR 正在使用 JQuery。在 jQuery(以及几乎任何其他 JS 框架)中,在“文档就绪”事件之后执行代码会更好。所以我将 SignalR 设置包装在 jQuery 文档就绪处理程序中(参见下面的代码)。 此外,我删除了 hubConnetion 全局变量,因为全局变量不好 + 在包装在 jQuery 文档就绪处理程序中之后,变量是该处理程序的本地变量,并且无论如何都无法在控制器代码中访问......

2) 主要问题恕我直言(SignalR client API 的一部分):

通常在调用 start 方法之前注册事件处理程序 建立连接。如果你想注册一些事件 建立连接后的处理程序,您可以这样做,但是您 在调用 启动方法。造成这种情况的一个原因是在一个 应用程序,但您不想触发 OnConnected 事件 每个集线器,如果您只使用其中一个集线器。当。。。的时候 连接建立后,Hub 上存在客户端方法 proxy 告诉 SignalR 触发 OnConnected 事件。 如果你 在调用 start 方法之前不要注册任何事件处理程序,你 将能够调用集线器上的方法,但集线器的 OnConnected 方法不会被调用,也不会从 服务器

您的事件处理程序是在控制器工厂方法中设置的,该方法在连接start() 方法之后调用。 尝试在调用 start() 之前添加 临时 处理程序,如下所示:

$.connection.tasklistHub.client.getTask = function () ;

3) 为确保问题出在 SignalR 而不是 Angular,我打开了服务器端和客户端 tracing。完成上述所有更改后,客户端成功接收到来自服务器的事件:

SignalR: Triggering client hub event 'getTask' on hub 'TasklistHub'

但 Angular 未能使用收到的数据更新 div。解决方案是使用this article about using SignalR and Angular together 中提到的$rootScope.$apply 函数。现在一切都按预期工作。请参阅下面的完整代码。

旁注:我知道这只是示例代码。在任何现实世界的项目中,我都会考虑将 SignalR 集线器包装在客户端上的某种服务中,例如上面提到的文章中或使用 this library(看起来很优雅)

我还根据同一文档收回我之前关于客户端处理程序名称的答案,客户端方法名称匹配不区分大小写...

Index.cshtml

<html lang="en" ng-app="SignalR">
    <head>
        <meta charset="utf-8" />
        <title>SignalR & AngularJS</title>
        <script src="~/Scripts/jquery-1.6.4.js"></script>
        <script src="~/Scripts/jquery.signalR-2.2.0.js"></script>
        <script src="~/signalr/hubs"></script>
        <script src="~/Scripts/angular.js"></script>

        <script type="text/javascript">
            $(function() 
                $.connection.hub.logging = true;

                // temporary handler to force SignalR to subscribe to server events
                $.connection.tasklistHub.client.getTask = function ()  ;

                $.connection.hub.start().done(function () 
                    $('#connectionStatus').text('Connected');
                    console.log('Now connected, connection ID =' + $.connection.hub.id);
                );
            );

            var SignalRControllers = angular.module('SignalRControllers', []);
            var SignalRApp = angular.module('SignalR', ['SignalRControllers']);
        </script>
        <script src="~/Scripts/app/TodayController.js"></script>
    </head>
<body>
    <div id="body">
        <div ng-view>
            <div ng-controller="TodayController">

                <div id="connectionStatus"></div>

                <div>Task</div>

                <input id="taskName" type="text"/>
                <input type="button" name="Send Task" value="Send Task" data-ng-click="sendTask()" />
            </div>
        </div>
    </div>
</body>
</html>

TodayController.js

SignalRControllers.controller('TodayController', [
        '$scope', '$http', '$rootScope',
        function ($scope, $http, $rootScope) 
            $scope.sendTask = function() 
                $.connection.tasklistHub.server.sendTask($("#taskName").val());
            ;
            $scope.Task = "Empty";

            $.connection.tasklistHub.client.getTask = function (task) 
                console.log(task);
                $rootScope.$apply(function () 
                    $scope.Task = task;
                );             
            ;
        
    ]
);

【讨论】:

错误信息是什么。有没有 ?打开 Firebug 或 Chrome 开发者工具窗口并查看控制台消息。尝试在$.connection.hub.start();之前添加这个$.connection.hub.logging = true; $.connection.hub.error(function (error) console.error('SignalR error: ' + error); ); 我添加了您的代码,但没有错误消息,如果我开始调试,当我在单击时调用 SendTask 时,它会像预期的那样进入该集线器功能,但在 Clients.All.GetTask(Name); 之后什么都没有发生了,hubConnetion.client.getTask= function (Task) 永远不会被调用 服务器的响应是传递给浏览器的? (请参阅浏览器开发工具中的网络选项卡) 没有响应,但是之后我把hubConnetion.client.getTask= function (Task) 放在控制器外面,它工作了,但是仍然没有来自服务器的响应,只有这样的方法send?transport....跨度> 嗯,它可能与 Angular 如何运行你的控制器构造函数有关。我不是 Angular 方面的专家,所以我帮不了你。我建议看一些关于如何将 SignalR 与 Angular 一起使用的教程(例如 one)或 this project

以上是关于SignalR 客户端在 AngularJs 控制器中不起作用的主要内容,如果未能解决你的问题,请参考以下文章

如何从angularJs连接signalR

AngularJS 与 SignalR

通过查询字符串传递“承载”时,SignalR 身份验证失败

SignalR 控制台应用程序示例

ASP.NET Core SignalR :SignalR Javascript 客户端

SignalR入门