首页 文章

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

提问于
浏览
6

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

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

我已经阅读了一些例子this question about using SignalR in a service(我已经使用了第二个解决方案)和this articlethe official docs但是即使应用这些概念它似乎也不起作用 .
(所以,或者我仍然缺少一些东西,但我找不到...)

The client connects to the Message Hub successfully 如果我点击按钮, the method is getting hit 但是 I don't get any message 而我在Chrome控制台中收到此警告:

警告:找不到名为“SendAsync”的客户端方法 .

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

问题是: what am I doing wrong? Is the error on the back-end side or in the Angular side?


我和你分享我的所有代码 (the button and the service to call the controller method are not relevant since the call to the service goes fine)

Startup.cs

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

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

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

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 回答

  • 8

    在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,我们会收到错误:所有客户端代理方法必须返回'System.Threading.Tasks.Task'

相关问题