【问题标题】:SignalR workaround to get client data from serverSignalR 解决方法从服务器获取客户端数据
【发布时间】:2018-01-26 15:50:56
【问题描述】:

我知道当调用来自服务器时,SignalR 不能从客户端返回。在 SignalR 的 github 存储库中,我要求提供一种解决方法 (https://github.com/aspnet/SignalR/issues/1329),他们建议我通过将结果从客户端发送到服务器到集线器中的另一个方法来获取结果,因此使用 TaskCompletionSource 和一些连接元数据来捕获结果,但我一直坚持如何做到这一点

控制器服务器:

[HttpPut("send/{message}")]
public async Task<IActionResult> SendMessage(string message)
{
    if (!ModelState.IsValid) return BadRequest(ModelState.Values);

    string connectionId = Request.Headers["connectionId"];
    await _chatHubContext.Clients.Client(connectionId).InvokeAsync("send");

    // Catch the call of MessageReceived and get the chat status

    return new OkObjectResult(new EmptyJsonResult() { Result = "OK" }); 

}

集线器服务器

public class ChatHub : Hub
{
    public Task MessageReceive(bool chatStatus)
    {
        // Tell controller that message is received
    }
}

Angular 4 客户端

import { Component, Inject } from '@angular/core';
import { HubConnection } from '@aspnet/signalr-client';

@Component({
  selector: 'chat',
  templateUrl: './chat.component.html',
  styleUrls: ['./chat.component.css']
})
/** chat component*/
export class ChatComponent {
  hubConnection: HubConnection;
  chatStatus = false;

  /** chat ctor */
  constructor( @Inject('BASE_URL') private originUrl: string) {
    this.hubConnection = new HubConnection(`${this.originUrl}chat`);

    setInterval(() => {
      this.chatStatus = !this.chatStatus;
    },
      5000);

    this.hubConnection
      .start()
      .then(() => {
        this.hubConnection.on('send', (message: string) => {
          if (this.chatStatus) {
            //send message
          }
          this.hubConnection
            .invoke('messageReceived', this.chatStatus);
        });
      });

  }
}

正如您在这段代码中看到的那样,我不知道在控制器方法和 Hub 方法中做什么才能知道方法 MessageReceive 被调用并获取他的返回以将其发送回控制器请求。

【问题讨论】:

    标签: angular asp.net-core-2.0 asp.net-core-signalr taskcompletionsource


    【解决方案1】:

    “稍微修改一下连接元数据和TaskCompletionSource,你也可以让它看起来很像一个返回值的方法调用。”

    控制器服务器

    注入HttpConnectionManager

    // using Microsoft.AspNetCore.Http.Connections.Internal;
    
    public async Task<IActionResult> SendMessage(string message)
    {
        string connectionId = Request.Headers["connectionId"];
    
        var chatStatus = await Send(connectionId, message);
    
        return new OkObjectResult(new { Result = "OK", ChatStatus = chatStatus });
    }
    
    private async Task<bool> Send(string connectionId, string message)
    {
        var tcs = new TaskCompletionSource<bool>();
    
        _connectionManager.TryGetConnection(connectionId, out HttpConnectionContext connection);
    
        connection.Items.Add("tcs", tcs);
    
        await _chatHubContext.Clients.Client(connectionId).SendAsync("send", message);
    
        var chatStatus = await tcs.Task;
    
        connection.Items.Remove("tcs");
    
        return chatStatus;
    }
    

    中心服务器

    public Task MessageReceived(bool chatStatus)
    {
        Context.Items.TryGetValue("tcs", out object obj);
    
        var tcs = (TaskCompletionSource<bool>)obj;
    
        tcs.SetResult(chatStatus);
    
        return Task.CompletedTask;
    }
    

    Angular 4 客户端

    // No change
    

    【讨论】:

    • 检查服务器端异常:#163, #1026
    • 是的,只是使用了错误的方法名称。但是您的解决方案非常有效,这正是我想要的。非常感谢你,你是我的救星:)
    • 嘿,这个解决方案不再适用于 aspnet/signalr 1.1.0 版。原因 SignalR 不再使用 Microsoft.AspNetCore.Sockets。您知道如何改进您的答案以使其与 Signalr 1.1.0 一起使用吗?
    • Microsoft.AspNetCore.SignalR 1.1.0 的更新解决方案。
    • 太好了,它工作得很好。我是如此接近但错过了好包:Microsoft.AspNetCore.Http.Connections.Internal。再次感谢您
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-17
    相关资源
    最近更新 更多