使用SignalR Core将消息从Controller方法发送到Angular

时间:2018-05-30 15:29:50

标签: c# angular asp.net-core signalr asp.net-core-signalr

我尝试将SignalR用于Asp Net Core 2.1,以便从控制器方法发送消息,该方法从Angular中的测试按钮触发调用。
我期望的行为是当我点击按钮时,我的服务调用控制器方法,该方法发送测试消息。然后,我将简单地记录消息。

我想在服务中管理它,以避免所有组件中的代码重复。

我已经阅读了一些示例,例如this question about using SignalR in a service(我已经使用过第二种解决方案)和this article以及the official docs但是即使应用了这些概念,它也不会;似乎工作。
(所以,或者我绝对是以错误的方式应用它们,或者仍然缺少某些东西,但我无法找到...)

客户端成功连接到消息中心,如果我点击按钮,方法就会受到影响,但我没有收到任何消息,而我在Chrome控制台中收到此警告:

  

警告:没有名称为' SendAsync'的客户端方法找到。

发送消息的工作正常,问题就在于接收消息......

问题是:我做错了什么?错误是在后端还是在Angular端?

我与你分享我的所有代码(调用控制器方法的按钮和服务不相关,因为对服务的调用很顺利)

  

> Startup.cs

public void ConfigureServices(IServiceCollection services)
{
   //...
   services.AddSignalR();
}
//...
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
   //...
   app.UseSignalR(routes =>
   {
      //...
      routes.MapHub<MessageHub>("/messagehub");
      //...
   });
}
  

&GT; MessageHub.cs

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

&GT; MessageController.cs

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

&GT; communication.service.ts

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

1 个答案:

答案 0 :(得分:10)

在signalr core 2.1中,您可以使用强类型集线器在接口中声明可以在客户端上调用哪些操作:

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

如果您不使用强类型集线器,那么在客户端调用相同的方法就会变成:

public class MessageHub : Hub
{
    public async Task SendMessage(string title, string user, string message)
    {
        await Clients.All.SendAsync("SendMessageToClient", title, user, message);
    }
}

在这种情况下,您可以在客户端代理上使用SendAsync方法,它的第一个参数是您要调用的方法的名称。

更新: 当我们使用接口定义强类型集线器时,所有接口方法都必须返回Task。使用自定义方法,signalr生成调用SendCoreAsync的方法。这允许我们异步调用这些方法。

如果接口方法的返回类型不是Task,我们会收到错误:所有客户端代理方法必须返回&#39; System.Threading.Tasks.Task&#39;