jeudi 25 avril 2019

Why does connection.InvokeAsync trigger a callback while other methods don't?

I have a .NET Core application that makes use of SignalR hubs.

After executing some business logic, mediator.Publish is called with some payload. The payload then reaches a dispatcher that uses an IHubContext to send an appropriate message.

public class NotificationDispatcher : INotificationHandler<Notification>
{
    private readonly IHubContext<NotificationDispatcher> _hubContext;

    public NotificationDispatcher(IHubContext<NotificationDispatcher> hubContext)
    {
        _hubContext = hubContext;
    }

    public Task Handle(Notification notification, CancellationToken cancellationToken) =>
        _hubContext
            .Clients
            .All
            .SendAsync("Notify", notification, cancellationToken);
}

The code is working, but I would like to have integration tests for it.

I'm using Microsoft.AspNetCore.Mvc.Testing and am instantiating a connection like so

private static async Task<HubConnection> StartConnectionAsync(HttpMessageHandler handler, string hubName)
{
    var hubConnection = new HubConnectionBuilder()
        .WithUrl($"ws://localhost/{hubName}", o =>
        {
            o.HttpMessageHandlerFactory = _ => handler;
        })
        .Build();

    await hubConnection.StartAsync();

    return hubConnection;
}

then, for assertion purposes, I subscribe to the "Notify" event using connection.On("Notify", notification => {}).

Then I call the endpoint that is supposed to emit an event using WebApplicationFactory<Startup>

await factory.CreateClient().PostAsJsonAsync("/notify", notification);

All of the "event publishing" code is executed successfully (verified through breakpoints). The dispatcher is called with the correct arguments, but the handler that is passed inside connection.On is never executed.

If, however, I add a Notify method inside the hub itself:

public Task Notify(Notification notification) =>
    Clients
        .All
        .SendAsync(nameof(Notification), notification);

and then call connection.InvokeAsync("Notify", notification);, the handler that's passed in connection.On is executed.

Expected:

After the dispatcher has been called, the handler that is passed inside connection.On to be executed.

Actual:

The handler that is passed inside connection.On is never executed unless I use connection.Invoke.

Aucun commentaire:

Enregistrer un commentaire