【问题标题】:Failed to invoke signalR调用 signalR 失败
【发布时间】:2020-02-11 18:49:37
【问题描述】:

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

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");
            });

错误记录

失败:Microsoft.AspNetCore.SignalR.Internal.DefaultHubDispatcher[8] 未能调用集线器方法“发送”。 System.IO.InvalidDataException:调用提供 1 个参数,但目标需要 0。 在 Microsoft.AspNetCore.SignalR.Protocol.JsonHubProtocol.BindArguments(JArray args,IReadOnlyList`1 paramTypes) 在 Microsoft.AspNetCore.SignalR.Protocol.JsonHubProtocol.ParseMessage(Utf8BufferTextReader textReader, IInvocationBinder binder)

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

【问题讨论】:

  • 你的 hub 方法被称为 Send1 但你正在调用 Send
  • 我想从 OnProvideData 方法调用 Send。
  • 这是您在客户端上监听的事件。但在客户端上,您还尝试调用集线器上不存在的“发送”。看我的回答。

标签: angular asp.net-core signalr


【解决方案1】:

您在客户端调用的方法名称必须与您在 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 个参数。

【讨论】:

  • 我想从控制器中的 OnProvideData 方法调用 Send,而不是在 Hub 的 Send1 中。
  • 我添加了更多细节。您想从客户端调用集线器上的发送。这就是错误消息和您的代码所说的 (this._hubConnection.invoke('Send', "hey"))
  • 您好,感谢您的耐心等待和时间。我明白了。我的最终目标是在客户端侦听服务器事件时在客户端上实现逻辑。我的意思是当 this._hubconnection.on 成功时,我想使用 this.disabled = false 在我的客户端中启用一个按钮。你能建议我如何整合它。
  • 您最初的问题是关于未能调用 signalR。我的回答应该解决这个问题。现在你的跟进:这也应该被修复,因为这就是你已经在你的代码中做的事情。
  • 您好,原来的问题适合您的回答。但后续行动不起作用。我想从我的控制器而不是我的集线器实现 hubconnection.on 功能。
【解决方案2】:

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

步骤 1

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

services.AddSignalR();

startup.cs --&gt; Configure() 应该包含您的映射,例如:

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

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

第二步

您的 hub 类可以简单地继承自 : 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);
    }
}

第三步

根据您想要通知正在监听您集线器的所有客户端(或特定客户端)的后端代码的时间/位置,您可以通过执行类似操作简单地发出您想要传输的数据。

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));
}

第四步

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

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);
    }
 }

【讨论】:

  • 我正在尝试在 private void OnProvideData(DataAndHeader dh) 方法中实现它 是否正确或者我应该进行任何更改。因为我无法从我的控制器接收任何数据。
  • 嗯,目前看起来还不是 100% 准确。从我的示例的第 1 步看,您的 startup.cs 看起来如何?
  • 在您的“SignalRhub”部分,任务 Send1() 似乎没有做任何事情。您只是想将消息从服​​务器推送到客户端,对吗?或者您是否还想从客户端发送数据以触发集线器中的 Send1() 方法?因此,您的客户应该订阅http://localhost:5000/message/Send - 就像您所做的那样。所以现在你只需要从服务器代码触发发射事件。函数是private/public都没有关系,只要触发即可。
  • 你说的是对的。我只想将消息从服​​务器推送到客户端。我不确定是否在服务器端触发了发出事件。我只希望 _hubconnection.on 正常运行,以便我可以记录数据并启用按钮。
  • 当您将您的客户端连接到服务器时,您是否遇到任何错误?如果没有,您可能已连接。如果您使用 chrome 之类的浏览器,则可以在开发者工具中检查网络流量。大多数可能建立了一个 websocket 连接。我建议您在控制器中创建 API 路由以从服务器触发事件​​。但是你还需要通过请求触发 API 路由,GET 请求是最简单的。查看第 4 步底部,将其替换为您自己的代码,例如:`_hubContext.Clients.All.SendAsync("Send", data);`
猜你喜欢
  • 1970-01-01
  • 2016-02-15
  • 2019-01-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多