简体   繁体   English

如何将 SignalR 与 Angular 7 应用程序连接起来

[英]How to hook up SignalR with an Angular 7 application

I simply cannot figure out how to make a signalr connection from Angular.我根本无法弄清楚如何从 Angular 建立信号连接。

Using the following tutorial at https://docs.microsoft.com/en-us/aspnet/signalr/overview/getting-started/tutorial-getting-started-with-signalr-and-mvc使用https://docs.microsoft.com/en-us/aspnet/signalr/overview/getting-started/tutorial-getting-started-with-signalr-and-mvc 上的以下教程

I've added a new SignalR 2.4.0 project to an existing .Net 4.6 solution in vs2017.我在SignalR向现有的 .Net 4.6 解决方案添加了一个新的SignalR 2.4.0 项目。

I also have an Angular 7 application to which I've added the SignalR package via npm install @aspnet/signalr我还有一个Angular 7应用程序,我通过npm install @aspnet/signalr添加了SignalR

Now I'm trying to hook up a simple connection between client and server, but can't figure out how to establish the initial connection.现在我试图在客户端和服务器之间建立一个简单的连接,但不知道如何建立初始连接。

My front end keeps throwing an exception:我的前端不断抛出异常:

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

Error: Cannot send data if the connection is not in the 'Connected' State.错误:如果连接未处于“已连接”状态,则无法发送数据。

In my front end search component, I've added some fields for testing:在我的前端搜索组件中,我添加了一些用于测试的字段:

 <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>

And in my ts file :在我的 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 = ''; } }

and on the c# side, I added a SignalR Hub Class (v2) file, BroadcastHub.cs在 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); } } } }

as well as a Startup.cs file :以及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()); } } }

I just spent two days trying to figure out this same thing.我只是花了两天时间试图弄清楚同样的事情。 I finally got it to work and these are the few things that i had to do:我终于让它工作了,这些是我必须做的几件事:

1) You noted that using the @aspnet/signalr package was incorrect for .Net framework, and that is correct. 1) 您注意到使用@aspnet/signalr包对于 .Net 框架是不正确的,这是正确的。 You need the signalr package ( npm install signalr ).您需要signalr包( npm install signalr )。

2) This is the most critical part of the whole process. 2)这是整个过程中最关键的部分。 SignalR has a dependency on jQuery . SignalR依赖于jQuery You have to include jQuery before including the signalr script.包含信号脚本之前,必须包含 jQuery。 In the angular.json file, under the scripts section, you need to include:angular.json文件的scripts部分下,您需要包含:

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

in that exact order.按照那个确切的顺序。 On start up of your project, it will load jQuery first, then the signalR script.在您的项目启动时,它会首先加载 jQuery,然后是 signalR 脚本。

Many other stackover flow answers answering the question in reply to this error:许多其他 stackover 流答案回答了这个错误的问题:

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

tell you to write import * as $ from "jquery" in the component you are wanting to use jQuery in. However, it is NOT correct to do this.告诉您在要在其中使用 jQuery 的组件中将import * as $ from "jquery"写入。但是,这样做是正确的。 The reason is, according to this angular article about global scripts , using the import syntax will include it in the module load and put it in the vendor.js file that is created from running an ng build command.原因是,根据这篇关于全局脚本的角度文章,使用import语法会将其包含在module加载中,并将其放入通过运行ng build命令创建的vendor.js文件中。 The reason this is a problem is because jQuery will get loaded first from your angular.json, then signalR will be loaded, then the module from the vendor.js will RELOAD jQuery and unattach all the events that were just attached to jQuery from signalR.这是一个问题的原因是因为 jQuery 将首先从您的 angular.json 加载,然后将加载 signalR,然后来自 vendor.js 的模块将重新加载 jQuery 并取消附加所有刚刚从 signalR 附加到 jQuery 的事件。

3) Since you noticed you were using the .Net Core version of signalr, you wont have access to the HubConnectionBuilder when trying to instantiate a new HubConnection in your angular component. 3) 由于您注意到您使用的是 .Net Core 版本的信号器, HubConnectionBuilder在尝试在角度组件中实例化新的HubConnectionBuilder时,您将无法访问HubConnectionBuilder

Instead, when the signalr script gets executed, it will attach additional events to the $ in your code.相反,当信号脚本被执行时,它会将额外的事件附加到代码中的$上。 Note: if you get errors on build or in compile time from your ts files, make sure you've included the @types/signalr and @types/jquery from npm注意:如果您在构建或编译时从 ts 文件中遇到错误,请确保您已包含 npm 中的@types/signalr@types/jquery

To set up a new hub connection, use $.hubConnection("your-url-here/signalr") .要设置新的集线器连接,请使用$.hubConnection("your-url-here/signalr") This will attach to your server's Hub when running.这将在运行时附加到您服务器的集线器。 Note: I stored the result from this as a variable called hubConnection in my angular component注意:我将此结果存储为一个名为hubConnection的变量在我的角度组件中

On your server code (.cs file), where you have your Hub class, you will need to add above the class name: [HubName("YourHubName")] .在您拥有 Hub 类的服务器代码(.cs 文件)上,您需要在类名上方添加: [HubName("YourHubName")] So in your case your .cs file would look something like this at the top:所以在你的情况下,你的 .cs 文件在顶部看起来像这样:

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

You will most likely have to include this at the top of your .cs file: using Microsoft.AspNet.SignalR.Hubs;您很可能必须将其包含在 .cs 文件的顶部: using Microsoft.AspNet.SignalR.Hubs;

Then in your Angular Component you set up a proxy to attach to that Hub on your server The very next line after instantiating your new hubConnection, write:然后在你的 Angular 组件中设置一个代理以附加到服务器上的集线器在实例化新的 hubConnection 后的下一行,写:

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

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

After you have made your proxy, you can then attach listeners to listen to events emitted from the server, or you can invoke server functions from your angular components.创建代理后,您可以附加侦听器以侦听从服务器发出的事件,或者您可以从 Angular 组件调用服务器函数。

I followed this example here to learn how to set up calling events and listening to server events.我在这里学习了这个例子来学习如何设置调用事件和监听服务器事件。 Yes it is angular 2, but the functions from signalr all still work the same in my angular 7 app.是的,它是 angular 2,但信号器的功能在我的 angular 7 应用程序中仍然有效。

Short answer: use proxy.on('eventname') to listen to events from the server, and use proxy.invoke('eventname') to call functions on your Hub from your angular components.简短回答:使用proxy.on('eventname')侦听来自服务器的事件,并使用proxy.invoke('eventname')从您的proxy.invoke('eventname')组件调用集线器上的函数。

Lastly, a few notes in your cs files.最后,在你的 cs 文件中有一些注释。 In my Startup.cs, the only thing i have for mapping signalr is app.MapSignalR() .在我的 Startup.cs 中,我唯一可以映射信号器的是app.MapSignalR() I did not go into many details regarding other properties to set like you have done, but that may be another cause of some issues?我没有像您那样详细介绍要设置的其他属性,但这可能是导致某些问题的另一个原因?

  • Angular app角度应用

Install signalR package安装signalR包

npm i @aspnet/signalr --save npm i @aspnet/signalr --save

import { Component, OnInit } from '@angular/core';
import { HubConnection } from '@aspnet/signalr';
import * as signalR from '@aspnet/signalr';

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

  private hubConnection: HubConnection;

  public ngOnInit() {
    this.hubConnection = new signalR.HubConnectionBuilder()
      .withUrl("http://localhost:50930/pushNotification").build();

    this.hubConnection.start().then(() => {
      console.log("connection started");
    }).catch(err => console.log(err));

    this.hubConnection.onclose(() => {
      debugger;
      setTimeout(() => {
        debugger;
        this.hubConnection.start().then(() => {
          debugger;
          console.log("connection started");
        }).catch(err => console.log(err));
      }, 5000);
    });

    this.hubConnection.on("clientMethodName", (data) => {
      debugger;
      console.log(data);
    });

    this.hubConnection.on("WelcomeMethodName", (data) => {
      debugger;
      console.log(data);
      this.hubConnection.invoke("GetDataFromClient", "user id", data).catch(err => console.log(err));
    });
  }

  public stopConnection() {
    this.hubConnection.start().then(() => {
      console.log("stopped");
    }).catch(err => console.log(err));
  }
}
  • Web API with netcoreapp2.2使用netcoreapp2.2 的Web API

    Install Microsoft.AspNetCore.SignalR安装Microsoft.AspNetCore.SignalR

Startup.cs启动文件

Client is running on port 4200 (" http://localhost:4200 ").客户端在端口 4200(“ http://localhost:4200 ”)上运行。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace SignalRWebApp
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

            services.AddCors(option =>
            {
                option.AddPolicy("CorsPolicy", builder =>
                         builder.WithOrigins("http://localhost:4200")
                        .AllowAnyMethod()
                        .AllowAnyHeader()
                        .AllowCredentials());
            });
            services.AddSignalR();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseCors("CorsPolicy");

            app.UseSignalR(routes =>
            {
                routes.MapHub<SignalHub>("/pushNotification");
            });

            app.UseHttpsRedirection();
            app.UseMvc();
        }
    }
}

SignalHub.cs信号中心

using Microsoft.AspNetCore.SignalR;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace SignalRWebApp
{
    public class SignalHub : Hub
    {
        public void GetDataFromClient(string userId, string connectionId)
        {
            Clients.Client(connectionId).SendAsync("clientMethodName", $"Updated userid {userId}");
        }

        public override Task OnConnectedAsync()
        {
            var connectionId = Context.ConnectionId;
            Clients.Client(connectionId).SendAsync("WelcomeMethodName", connectionId);
            return base.OnConnectedAsync();
        }

        public override Task OnDisconnectedAsync(Exception exception)
        {
            var connectionId = Context.ConnectionId;
            return base.OnDisconnectedAsync(exception);
        }
    }
}

Now send signalR message like the below example现在像下面的例子一样发送signalR消息

[Route("api/[controller]")]
    [ApiController]
    [EnableCors("CorsPolicy")]
    public class ValuesController : ControllerBase
    {
        private IHubContext<SignalHub> _hub;
        public ValuesController(IHubContext<SignalHub> hub)
        {
            _hub = hub;
        }

        // GET api/values
        [HttpGet]
        public ActionResult<IEnumerable<string>> Get()
        {
            _hub.Clients.All.SendAsync("clientMethodName", "get all called");
            return new string[] { "value1", "value2" };
        }

        // GET api/values/5
        [HttpGet("{connectionId}")]
        public ActionResult<string> Get(string connectionId)
        {
            _hub.Clients.Client(connectionId).SendAsync("clientMethodName", "get called");
            return "value";
        }
    }
}

Github GitHub

Was just researching this subject myself, and found npm package ng2-signal.我自己只是在研究这个主题,发现了 npm 包 ng2-signal。 Maybe something to look into yourself?也许有些东西要审视自己?

Are you sure that the hubEndpoint is correct?您确定 hubEndpoint 是正确的吗? It seems like the hub is part of the angular routing (judging by the way you are writing it).似乎集线器是角度路由的一部分(根据您编写它的方式来判断)。 Try to set the full path (ex. https://www.myapp.com/SynBroadcastHub/BroadcastMessage )尝试设置完整路径(例如https://www.myapp.com/SynBroadcastHub/BroadcastMessage

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何将observablecollection成员连接到应用程序资源(resx)文件 - How to hook up observablecollection member to application resources (resx) file 如何钩住一个应用程序? - How to hook an application? 如何验证从 Angular 应用程序与 Azure 函数(协商)建立的连接,该应用程序又与 Azure SignalR 服务连接? - How to authenticate the connections made to Azure Function (negotiate) from angular application which in turn connects with Azure SignalR Service? 扩展方法如何挂钩 - How extension methods hook up 如何确保与.NET客户端的SignalR连接正常? - How to ensure That The SignalR Connection to .NET Client Is Up? 如何将应用程序挂钩到特定键? - How to Hook an application to a particular key? 如何在SignalR Hub类中设置应用程序变量? - How to set Application Variable in SignalR Hub class? 如何在Chrome上获取用于角度应用程序的系统位置(区域)? - How to pick up system location(region) on Chrome for an angular application? 设置鼠标钩而不删除当前正在运行的应用程序? - Setting up mouse hook without removing currently running application? 在第三方应用程序的AppendMenu之后挂接click事件 - Hook up click event after AppendMenu of 3rd party Application
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM