首页 > 解决方案 > 如何将 SignalR 与 Angular 7 应用程序连接起来

问题描述

我根本无法弄清楚如何从 Angular 建立信号器连接。

在https://docs.microsoft.com/en-us/aspnet/signalr/overview/getting-started/tutorial-getting-started-with-signalr-and-mvc使用以下教程

SignalR在 vs2017 中的现有 .Net 4.6 解决方案中添加了一个新的 2.4.0 项目。

我还有一个Angular 7应用程序,我SignalR通过它添加了包npm install @aspnet/signalr

现在我试图在客户端和服务器之间建立一个简单的连接,但不知道如何建立初始连接。

我的前端不断抛出异常:

 core.js:15714 ERROR Error: Uncaught (in promise): Error: Cannot send data if the connection is not in the 'Connected' State.

错误:如果连接未处于“已连接”状态,则无法发送数据。

在我的前端搜索组件中,我添加了一些用于测试的字段:

<mat-form-field>
    <input matInput placeholder="message" [(ngModel)]="message">
</mat-form-field>
<button mat-button type="button" (click)="sendMessageToServer()"><span>Send</span></button>            
<p *ngFor="let m of messages">{{m}}</p>

在我的 ts 文件中:

// import other components/services here..
import { HubConnection, HubConnectionBuilder} from '@aspnet/signalr';

@Component({
  selector: 'app-my-search',
  templateUrl: './my-search.component.html',
  styleUrls: ['./my-search.component.scss']
})
export class MySearchComponent implements OnInit {

public hubConnection: HubConnection;
  public messages: string[] = [];
  public message: string;

   constructor() { }
   
   
  ngOnInit() {
   
    // SIGNALR MESSAGE HUB
    let builder = new HubConnectionBuilder();
    this.hubConnection = builder.withUrl('/SynBroadcastHub/BroadcastMessage').build();  // see startup.cs
    this.hubConnection.on('notifyUser', (message) => {
      this.messages.push(message);
      console.log(message);
    });
    this.hubConnection.start();
  }

  // signalr, send msg from client
  sendMessageToServer() {
    this.hubConnection.invoke('MessageToServer', this.message);
    this.message = '';
  }


}

在 c# 方面,我添加了一个SignalR Hub Class (v2)文件 BroadcastHub.cs

using Microsoft.AspNet.SignalR;

namespace SynBroadcastHub
{
    public class BroadcastHub : Hub
    {        
        /// Message to client 
        public void BroadcastMessage(string data)
        {
            Clients.Caller.notifyUser(data);
        }
    
        
        /// Message from client application; broadcast to all clients if requested.                
        public void MessageToServer(string data, bool notifyAllClients = false)
        {
            if (notifyAllClients)
            {
                Clients.All.NotifyAllClients(data);
            }
        }
    }
}

以及一个Startup.cs文件:

using Microsoft.Owin;
using Microsoft.AspNet.SignalR;
using Owin;

[assembly: OwinStartup(typeof(SynBroadcastHub.Startup))]

namespace SynBroadcastHub
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            HubConfiguration cfg = new HubConfiguration();
            app.MapSignalR<PersistentConnection>("BroadcastHub/BroadcastMessage");
            app.MapSignalR(cfg);
            app.MapSignalR();

            //app.MapSignalR<NotifyHub>("notify"); ???
        }
         public override Task OnDisconnected(bool stopCalled)
        {
            return Clients.All.leave(Context.ConnectionId, System.DateTime.Now.ToString());
        }

        public override Task OnConnected()
        {
            return Clients.All.joined(Context.ConnectionId, DateTime.Now.ToString());
        }

        public override Task OnReconnected()
        {
            return Clients.All.rejoined(Context.ConnectionId, DateTime.Now.ToString());
        }
    }
}

标签: c#angularsignalrsignalr-2

解决方案


我花了两天时间试图弄清楚同样的事情。我终于让它工作了,这些是我必须做的几件事:

1)您注意到@aspnet/signalr对于 .Net 框架使用该包是不正确的,这是正确的。您需要signalr包 ( npm install signalr)。

2)这是整个过程中最关键的部分。SignalR依赖于jQuery. 在包含信号器脚本之前,您必须包含 jQuery 。在文件中的部分下,您需要包括:angular.jsonscripts

"./node_modules/jquery/dist/jquery.js", "./node_modules/signalr/jquery.signalR.js"

按照那个确切的顺序。在您的项目启动时,它将首先加载 jQuery,然后是 signalR 脚本。

许多其他stackover flow回答回答了这个错误的问题:

jQuery was not found. Please ensure jQuery is referenced before the SignalR client JavaScript file

告诉您import * as $ from "jquery"在要使用 jQuery 的组件中编写。但是,这样做是正确的。原因是,根据这篇关于全局脚本的角度文章,使用import语法会将其包含在module加载中,并将其放入通过运行命令vendor.js创建的文件中。ng build这是一个问题的原因是因为 jQuery 将首先从您的 angular.json 加载,然后将加载 signalR,然后 vendor.js 中的模块将重新加载 jQuery 并从 signalR 取消附加刚刚附加到 jQuery 的所有事件。

HubConnectionBuilder3) 由于您注意到您使用的是 .Net Core 版本的信号器,因此当您尝试在角度组件中实例化新的 HubConnection 时,您将无法访问。

相反,当信号器脚本被执行时,它会$在你的代码中附加额外的事件。注意:如果您在构建或编译时从 ts 文件中遇到错误,请确保您已包含来自 npm的@types/signalrand@types/jquery

要设置新的集线器连接,请使用$.hubConnection("your-url-here/signalr"). 这将在运行时附加到您服务器的集线器。注意:我将结果存储为hubConnection在我的角度组件中调用的变量

在您拥有 Hub 类的服务器代码(.cs 文件)上,您需要在类名上方添加: [HubName("YourHubName")]. 因此,在您的情况下,您的 .cs 文件在顶部看起来像这样:

[HubName("Broadcast")]    
public class BroadcastHub : Hub

您很可能必须将其包含在 .cs 文件的顶部: using Microsoft.AspNet.SignalR.Hubs;

然后在您的 Angular 组件中,您设置一个代理以附加到服务器上的该 Hub 实例化新的 hubConnection 后的下一行,编写:

this.hubConnection.createHubProxy("yourHubName");.

在你的情况下,this.hubConnection.createHubProxy("broadcast");

制作代理后,您可以附加侦听器以侦听从服务器发出的事件,或者您可以从 Angular 组件调用服务器函数。

我在这里按照这个例子来学习如何设置调用事件和监听服务器事件。是的,它是 Angular 2,但是 Signalr 的功能在我的 Angular 7 应用程序中仍然可以正常工作。

简短的回答:用于proxy.on('eventname')监听来自服务器的事件,并用于proxy.invoke('eventname')从您的角度组件调用集线器上的函数。

最后,在您的 cs 文件中添加一些注释。在我的 Startup.cs 中,我唯一用于映射信号器的是app.MapSignalR(). 我没有像您一样详细介绍要设置的其他属性,但这可能是导致某些问题的另一个原因?


推荐阅读