SignalR: Client awaiting long running server method leads to timeout on server-side
See original GitHub issueDescribe the bug
I have a small setup where a C# client invokes a server method without parameters, simply waiting for an URL to return (both are v3.0.0-preview5). In my test setup, the server works on that zip file for 100s. During the call, the server prepares a zip file and returns a link to that file once finished. The server frequently sends status updates to the client.
With logs enabled on both sides and also using wireshark, I can see that the client sends pings regularly. However, if I get the source code right, the server does not process these pings due to the pending await call. The following happes:
- after 30s, the server detects that no new message was received but continues without complains (I think this is intended)
- after 60s, the server detects again that no frame was received and tries to abort the connection, but the invoked method continues to run. At this point, the client is not receiving status updates anymore from the server.
- after 90s, the server detects again that no frame was received and tries to abort the connection, but the invoked method continues to run
- after 100s, the invoked method returns, and the connection is actually aborted.
OnDisconnectedAsyncis called. On the client side, the error “A task was cancelled” appears.
I am not sure if this is by design (i.e. ‘don’t use async/await for very long running methods’), or if this is a bug, since the pings from the client are not processed.
If it is by design, what is the recommended alternative, when a client needs to wait for a long running methods?
To Reproduce
Hub content:
using Microsoft.AspNetCore.SignalR;
using System;
using System.Threading.Tasks;
namespace WebApplication1
{
public class Broadcaster : Hub<IBroadcaster>
{
public Task<string> GetUrl()
{
int counter = 0;
return Task.Run(async () =>
{
for (int i = 0; i < 100; i++)
{
await Task.Delay(TimeSpan.FromSeconds(1));
await this.Clients.Client(this.Context.ConnectionId).SendProgress(counter, "Progress");
counter += 1;
}
return "url";
});
}
}
}
Callback interface:
using System.Threading.Tasks;
namespace WebApplication1
{
public interface IBroadcaster
{
Task SendProgress(double percent, string message);
}
}
Client:
_connection.On("SendProgress", (double percent, string message) =>
{
Console.WriteLine($"{percent,3:0}%: {message}\n");
});
var url = await _connection.InvokeAsync<string>("GetUrl");
Expected behavior
I would expect that during an active connection where the client sends ping messages and server sends status updates, the connection is not cancelled.
Additional context
Include the output of dotnet --info
.NET Core SDK (gemäß "global.json"):
Version: 3.0.100-preview5-011568
Commit: b487ff10aa
Laufzeitumgebung:
OS Name: Windows
OS Version: 10.0.17763
OS Platform: Windows
RID: win10-x64
Base Path: C:\Program Files\dotnet\sdk\3.0.100-preview5-011568\
Host (useful for support):
Version: 3.0.0-preview5-27626-15
Commit: 61f30f5a23
.NET Core SDKs installed:
2.1.602 [C:\Program Files\dotnet\sdk]
2.2.203 [C:\Program Files\dotnet\sdk]
3.0.100-preview5-011568 [C:\Program Files\dotnet\sdk]
.NET Core runtimes installed:
Microsoft.AspNetCore.All 2.1.9 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.All 2.2.4 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.App 2.1.9 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 2.2.4 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 3.0.0-preview5-19227-01 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.NETCore.App 2.1.9 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.2.4 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 3.0.0-preview5-27626-15 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.WindowsDesktop.App 3.0.0-preview5-27626-15 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Issue Analytics
- State:
- Created 4 years ago
- Comments:5 (4 by maintainers)

Top Related StackOverflow Question
Definitely agree. #5351 will make that work better since we won’t be blocking the message loop on running the Hub.
Another super hacky way you could do this is with the streaming support, since we don’t block the message loop on those requests. You can just stream only a single item back 😃. It’s a big hack though and a breaking change to your Client if you switch back and forth between streaming and non-streaming.
Thank @anurse for investigation. I switched now to a background service which handles the request to not block the hub for a long time. I no longer run into timeouts.
But more convenient would be to simply await the result 😃