无法调用 signalR

Failed to invoke signalR

我正在尝试使用 signalR 从 .net 核心服务器 (c#) 向我的客户端 (Angular) 发送通知。在触发事件时通知客户端。但我收到一个错误。 错误:错误:由于服务器

上的错误,无法调用 'Send'

Appcomponent.ts

ngOnInit() {
 this._hubConnection = new signalR.HubConnectionBuilder()
.configureLogging(signalR.LogLevel.Information)
.withUrl("http://localhost:5000/message/Send", this.transportType)
.build();
}
form(){
this._hubConnection.on("Send", (data) => {
  const received = `message: ${data}`;
  console.log(received);
  that.disabled = false;
});
  this._hubConnection.start()
.then(() =>
this._hubConnection.invoke('Send', "hey")
.catch(function (err) {
 console.error(err.toString());
})
)
.then(() =>
console.log('connected'))
.then(() => this._hubConnection.stop())
.then(() => console.log('Disconnected'))
.catch(e => console.error(e.message));
}

SignalR 集线器

public class DataHub : Hub
{
    public async Task Send1(string message1, string Root)
    {
        await Clients.All.SendAsync("Send1", message1);
    }
}

控制器

public class DataController : Controller
{
    private IHubContext<DrawingHub> _hubContext;
    public DataController(IHubContext<DataHub> hubContext)
    {
        _hubContext = hubContext;
    }
    private void OnProvideData(DataAndHeader data)
    {
        // server side code
        _hubContext.Clients.All.SendAsync("Send", data);
    }
}

Startup.cs

services.AddSignalR();

app.UseSignalR(routes =>
            {
                routes.MapHub<DrawingHub>("/message/Send");
            });

错误记录

fail: Microsoft.AspNetCore.SignalR.Internal.DefaultHubDispatcher[8] Failed to invoke hub method 'Send'. System.IO.InvalidDataException: Invocation provides 1 argument(s) but target expects 0. at Microsoft.AspNetCore.SignalR.Protocol.JsonHubProtocol.BindArguments(JArray args, IReadOnlyList`1 paramTypes) at Microsoft.AspNetCore.SignalR.Protocol.JsonHubProtocol.ParseMessage(Utf8BufferTextReader textReader, IInvocationBinder binder)

我想在事件中执行服务器端代码后调用signalr连接来通知客户端。有人可以指导我吗?提前致谢。

您在客户端调用的方法名称必须与您的 SignalR Hub 中的方法名称相同(但也允许使用小写方法)。

由于您的 Hub 方法被调用 Send1 而您的客户端调用 Send,因此找不到该方法。要解决此问题,您可以将 Hub 方法重命名为 Send 或更改客户端代码以调用 this._hubConnection.invoke('send1', "hey", "ho").

这是你要做的:

  • this._hubConnection.on("Send", ... 让客户端侦听名为 Send.

  • 的服务器事件
  • this._hubConnection.invoke('Send', "hey") 调用名为 Send 的服务器方法。这不存在!服务器方法称为 Send1!

  • public async Task Send1( string message1, string Root) 声明一个名为 Send1 的方法。在您的客户端中,您无处尝试调用 Send1,仅调用 Send(没有 1)。

  • await Clients.All.SendAsync("Send1", message1); 如果 Send1 将被调用,您将尝试向所有客户端发布 Send1 消息。但是没有客户端在监听 Send1,只监听 Send.

现在查看您的错误消息:Failed to invoke hub method 'Send'.它正在寻找一个集线器方法 Send 但它不存在,因为您将其称为 Send1

快速修复:只需将所有出现的 Send1 重命名为 Send。因为这就是您要在客户端上调用的内容。此外,您还必须使用 2 个参数调用它,而不是像现在这样的参数,因为 hub 方法有 2 个参数。

在您的 startup.cs 中,您应该注册 signalR 服务并在 http 请求管道中映射您的集线器,如果您还没有这样做的话。

步骤 1

startup.cs --> ConfigureServices()需要注册signalR服务,例如:

services.AddSignalR();

startup.cs --> Configure() 应包含您的映射,例如:

app.UseSignalR(routes =>
{
   routes.MapHub<YourHubClass>("/hub/test1");
   routes.MapHub<YourHubClass2>("/hub/test2");
});

如果需要,可以添加更多选项。但我相信默认值现在已经足够好了。

第 2 步

您的集线器 class 可以简单地继承自 : Hub 以进行测试。但是要显示一些控制台输出,您可以像这样覆盖虚拟 Hub 函数:

public class YourHubClass: Hub
{
    public override async Task OnConnectedAsync()
    {
        Console.WriteLine(Context.ConnectionId);
        await base.OnConnectedAsync();
    }

    public override async Task OnDisconnectedAsync(Exception ex)
    {
        Console.WriteLine(Context.ConnectionId);            
        await base.OnDisconnectedAsync(ex);
    }
}

步骤 3

根据您后端代码中的 when/where,您想要通知正在收听您的集线器的所有客户端(或特定客户端),您可以通过执行类似的操作来简单地发出您想要传输的数据这个。

var test1data = GetTest1Data();
await _hub.Clients.All.SendAsync("test1", test1data);

var test2data = GetTest1Data();
await _hub.Clients.All.SendAsync("test2", test2data);

其中 _hub 是在此范围内注入的依赖项。澄清一下:

private readonly IHubContext<YourHubClass> _hub;

public YourScopedConstructor(IHubContext<YourHubClass> hub) 
{
    _hub = hub ?? throw new ArgumentNullException(nameof(hub));
}

第 4 步

现在您可以连接并收听集线器了。例如:

public yourSubscribableSubject: BehaviorSubject<any> = new BehaviorSubject<any>(null);
private _baseUrl: string = "your base url";
private _frontendHubConnection: HubConnection;

this._frontendHubConnection = new HubConnectionBuilder()
        .withUrl(`${this._baseUrl}/hub/test1`) // or hub/test2
        .configureLogging(LogLevel.Information)
        .build();

this._frontendHubConnection
        .start()
        .then(() => console.log('SignalR - init'))
        .catch(err => console.log('Error while starting connection: ' + err));

 this._frontendHubConnection.on('test1', (data: any) => {
        console.log(data);
        this.yourSubscribableSubject.next(data);
    });

而要获取数据的任何其他组件,只需订阅 yourSubscribableSubject。希望对您有所帮助。

另外,如果你想触发数据从服务器从 API 端点发送到客户端,只需移动我在步骤 3 中建议的作用域代码。

public async Task<ActionResult> YourApiRoute()
{
    try
    {
        var test1data = GetTest1Data();
        await _hub.Clients.All.SendAsync("test1", test1data);
        return Ok();
    }
    catch (Exception e)
    {
        Console.WriteLine(e.Message);
        return StatusCode(StatusCodes.Status500InternalServerError);
    }
 }