2

I have an ASP.NET core WebApi project which also uses SignalR to communicate with clients. This app has an action that is called by a third-party service and requires that all clients currently connected should send some info back.

The SignalR infrastructure is already being used between the server and clients, so I added this particular action:

public async Task<ActionResult> GetClientInfo()
{
    await hubContext.Clients.All.GetClientInfo();

    //var infos...

    return Ok(infos);
}

So basically, this is what should happen:

  1. The third-party service calls the action
  2. The server asks all clients to send their info
  3. The server returns OK with all the client info

Is it possible to somehow wait and make sure that all clients sent their info before returning OK?

Ivan-Mark Debono
  • 15,500
  • 29
  • 132
  • 263
  • You can probably use this: https://learn.microsoft.com/en-us/aspnet/core/signalr/hubs?view=aspnetcore-7.0#client-results – Evk Jan 13 '23 at 06:04
  • @Evk That's what I'm looking at right now and I might use it within a loop of all connections. – Ivan-Mark Debono Jan 13 '23 at 06:20
  • Guess that's the best way. Just don't await them inside loop but await all at once after loop so that it happens in parallel. – Evk Jan 13 '23 at 07:11
  • @Evk How to wait all at once in parallel? – Ivan-Mark Debono Jan 13 '23 at 10:22
  • Instead of `await ...InvokeAsync()` do `tasks.Add(...InvokeAsync())` inside the loop, where `tasks` is a list of `Task`. Then after the loop await all at once via `await Task.WhenAll(tasks)`. – Evk Jan 13 '23 at 10:49

1 Answers1

0

I implemented the code as suggested like this:

public async Task<ActionResult> GetClientInfo()
{
    try
    {
        var tasks = new List<Task<IEnumerable<ClientInfo>>>();

        foreach (var client in cache.Clients.Values)
        {
            tasks.Add(Task.Run(async () =>
            {
                return await hubContext.Clients.Client(client.Id).GetClientInfo();
            }));
        }

        var list = await Task.WhenAll(tasks);
        return Ok(list);
    }
    catch (Exception ex)
    {
        return InternalServerError(ex);
    }
}

cache is MemoryCache implementation that is available throughout the whole app and is based on code similar to this SO answer.

Ivan-Mark Debono
  • 15,500
  • 29
  • 132
  • 263