从服务器获取客户端数据的 SignalR 解决方法
SignalR workaround to get client data from server
我知道当调用来自服务器时,SignalR 无法从客户端获得 return。在 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 方法并让他的 return 将其发回控制器请求。
"with a little hacking around with connection metadata and TaskCompletionSource
you could also probably make it look a lot like a method invocation returning a value."
控制器服务器:
注入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
我知道当调用来自服务器时,SignalR 无法从客户端获得 return。在 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 方法并让他的 return 将其发回控制器请求。
"with a little hacking around with connection metadata and
TaskCompletionSource
you could also probably make it look a lot like a method invocation returning a value."
控制器服务器:
注入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