Обходное решение SignalR для получения данных клиента с сервера

Я знаю, что SignalR не может получить возврат от клиента, когда вызов пришел с сервера. В github-репозитории SignalR я попросил обходной путь ( 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, и чтобы получить его возвращение, чтобы отправить его обратно в запрос контроллера.

1 ответ

Решение

"с небольшим взломом с метаданными соединения иTaskCompletionSourceВы также можете сделать его похожим на вызов метода, возвращающего значение."

Контроллер сервера:

впрыскивать ConnectionManager,

// using Microsoft.AspNetCore.Sockets;

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 DefaultConnectionContext connection);

    connection.Metadata.Add("tcs", tcs);

    await _chatHubContext.Clients.Client(connectionId).InvokeAsync("send", message);

    var chatStatus = await tcs.Task;

    connection.Metadata.Remove("tcs");

    return chatStatus;
}

Хаб-сервер:

public Task MessageReceived(bool chatStatus)
{
    Context.Connection.Metadata.TryGetValue("tcs", out object obj);

    var tcs = (TaskCompletionSource<bool>)obj;

    tcs.SetResult(chatStatus);

    return Task.CompletedTask;
}

Angular 4 клиент:

// No change
Другие вопросы по тегам