c# - 如何将 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());
}
}
}
解决方案
我花了两天时间试图弄清楚同样的事情。我终于让它工作了,这些是我必须做的几件事:
1)您注意到@aspnet/signalr
对于 .Net 框架使用该包是不正确的,这是正确的。您需要signalr
包 ( npm install signalr
)。
2)这是整个过程中最关键的部分。SignalR
依赖于jQuery
. 在包含信号器脚本之前,您必须包含 jQuery 。在文件中的部分下,您需要包括:angular.json
scripts
"./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 的所有事件。
HubConnectionBuilder
3) 由于您注意到您使用的是 .Net Core 版本的信号器,因此当您尝试在角度组件中实例化新的 HubConnection 时,您将无法访问。
相反,当信号器脚本被执行时,它会$
在你的代码中附加额外的事件。注意:如果您在构建或编译时从 ts 文件中遇到错误,请确保您已包含来自 npm的@types/signalr
and@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()
. 我没有像您一样详细介绍要设置的其他属性,但这可能是导致某些问题的另一个原因?
推荐阅读
- xml - 字段名称中的 FX 标记特殊字符
- java - 如何使用 OpenCSV 将 csv 导入 FX SimpleObjectProperties?
- java - Parallel Mergesort 基准测试 - 确定找到的阈值
- angular - 未捕获的类型错误:promise.fulfill 不是函数(与 Zone.js 冲突)(Angular 5)
- javascript - 更改 HTML 对象属性
- c# - 从控制器显示模态弹出 div
- asp.net-mvc - Visual Studio 2019 中的 MVC 不会像 2015 那样自动创建文件吗?
- java - 在 PlaybackSupportFragment (leanback) 中未调用 tickle()
- javascript - 在平移/缩放/旋转时通过几何图形推动正弦波
- clang - 使用 clang LLVM 延迟加载