问题描述
我试图将SignalR用于Asp Net Core 2.1,以便从控制器方法发送消息,该调用是从Angular中的测试按钮触发的.
我期望的行为是,当我单击按钮时,我的服务将调用controller方法,该方法发送测试消息.然后,我将简单地记录该消息.
I'm trying to use SignalR for Asp Net Core 2.1 in order to send a message from a controller method which call is triggered from a test button in Angular.
The behavior I'd expect is that when I click the button, my service invokes the controller method, which sends the test message. Then, I will simply log the message.
我想在服务中对此进行管理,以避免所有组件中的代码重复.
I want to manage this in a service in order to avoid code duplication in all of the components.
我已经阅读了一些示例,例如关于在服务中使用SignalR的问题(我使用了第二种解决方案)和本文和官方文档,但即使应用了这些概念,它似乎也不起作用.
(所以,或者我绝对会以错误的方式应用它们,或者仍然缺少某些东西,但我无法找出原因...)
I've read some examples like this question about using SignalR in a service (I've used the second solution) and this article and the official docs but even with applying these concepts it don't seems to work.
(So, or I'm absolutely applying them in a wrong way or there's still something missing but I can't find out what...)
客户端成功连接到消息中心,如果我单击按钮,则该方法被击中,但我没有收到任何消息,相反,我在Chrome控制台中收到此警告:
The client connects to the Message Hub successfully and if I click the button, the method is getting hit but I don't get any message and instead I get this warning in the Chrome console:
发送邮件效果很好,问题就在于接收邮件...
Sending messages works fine, the issue is just with receiving them...
问题是:我在做什么错?错误是在后端还是在Angular上?
我与您共享所有代码(由于调用该服务的操作正常,因此按钮和调用控制器方法的服务无关):
public void ConfigureServices(IServiceCollection services)
{
//...
services.AddSignalR();
}
//...
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
//...
app.UseSignalR(routes =>
{
//...
routes.MapHub<MessageHub>("/messagehub");
//...
});
}
public class MessageHub : Hub<ITypedHubClient>
{
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
}
public interface ITypedHubClient
{
Task SendAsync(string title, string name, string message);
}
IHubContext<MessageHub, ITypedHubClient> _messageHubContext;
public MessageController(IHubContext<MessageHub, ITypedHubClient> messageHubContext)
{
_messageHubContext = messageHubContext;
}
[HttpPost("Test")]
public async Task<IActionResult> Test()
{
try
{
await _messageHubContext.Clients.All.SendAsync("ReceiveMessage","test", "test");
return Ok(true);
}
catch (Exception e)
{
return BadRequest(e);
}
}
@Injectable()
export class CommunicationService {
private _hubConnection: HubConnection | undefined;
public async: any;
message = '';
messages: string[] = [];
private newmessage = new Subject<string>();
message$ = this.newmessage.asObservable();
constructor() {
this._hubConnection = new signalR.HubConnectionBuilder()
.withUrl('/messagehub')
//.configureLogging(signalR.LogLevel.Information)
.configureLogging(signalR.LogLevel.Debug)
.build();
this._hubConnection.start().catch(err => console.error(err.toString()));
this._hubConnection.on('SendMessage', (user: any, message:any) => {
const received = `Received: ${message}`;
//this.messages.push(received);
this.newmessage.next(received);
console.log("got something new...", received);
});
}
clear() {
this.newmessage.next("");
}
public sendMessage(): void {
const data = `Sent: ${this.message}`;
if (this._hubConnection) {
this._hubConnection.invoke('SendMessage', 'AAA' ,data);
}
this.messages.push(data);
}
}
推荐答案
在signalr核心2.1中,您可以使用强类型的集线器在接口中声明可以在客户端上调用哪些操作:
In signalr core 2.1 you can use strongly typed hubs to declare in an interface what actions can be called on the clients :
public class MessageHub : Hub<ITypedHubClient>
{
public async Task SendMessage(string title, string user, string message)
{
await Clients.All.SendMessageToClient(title, user, message);
}
}
public interface ITypedHubClient
{
Task SendMessageToClient(string title, string name, string message);
}
在控制器中:
IHubContext<MessageHub, ITypedHubClient> _messageHubContext;
public async Task<IActionResult> Test()
{
await _messageHubContext.Clients.All.SendMessageToClient("test", "test", "test");
return Ok("ok");
}
在客户端中:
_hubConnection.on('SendMessageToClient', (title, user, message) => {
const received = `title: ${title}, name: ${user}, message: ${message}`;
console.log(received);
});
如果您不使用强类型的集线器,则在客户端中调用相同的方法将变为:
If you don't use strongly typed hub, then to call the same method in the client it becomes :
public class MessageHub : Hub
{
public async Task SendMessage(string title, string user, string message)
{
await Clients.All.SendAsync("SendMessageToClient", title, user, message);
}
}
在这种情况下,您可以在客户端代理上使用SendAsync方法,它的第一个参数是您要调用的方法的名称.
In that case you can use the SendAsync method on the client proxy, it's first parameter is the name of the method you want to call.
更新:当我们定义带有接口的强类型集线器时,所有接口方法都必须返回Task.使用自定义方法,signaler生成调用SendCoreAsync的方法.这样我们就可以异步调用这些方法.
Update :When we define a strongly typed hub with an interface, all interface methods must return a Task. With custom methods, signalr generates methods that call SendCoreAsync. That allow us to call these methods asynchronously.
如果接口方法的返回类型不是Task,则会收到错误消息:所有客户端代理方法都必须返回'System.Threading.Tasks.Task'
If the return type of the interface methods is not a Task we get the error : All client proxy methods must return 'System.Threading.Tasks.Task'
这篇关于使用SignalR Core将消息从控制器方法发送到Angular的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!