Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Conversation

Copilot
Copy link
Contributor

@Copilot Copilot AI commented Oct 17, 2025

Fixes #11542

Summary

This PR implements cancellation support for regular (non-streaming) hub method invocations from the client. Previously, only streaming invocations could be cancelled by the client. Now, when a client passes a CancellationToken to InvokeAsync and cancels it, the server-side hub method will be cancelled as well.

Example Usage

Server-side hub method:

public class MyHub : Hub
{
    public async Task<string> LongRunningOperation(CancellationToken cancellationToken)
    {
        // This will be cancelled when client cancels the invocation
        await Task.Delay(TimeSpan.FromMinutes(5), cancellationToken);
        return "Completed";
    }
}

Client-side invocation:

var cts = new CancellationTokenSource();

// Start the invocation
var task = connection.InvokeAsync<string>("LongRunningOperation", cts.Token);

// Cancel it from the client
cts.Cancel();

// The server-side method will receive cancellation
await task; // Throws TaskCanceledException

Implementation Details

Client Changes

  • Updated HubConnection.InvokeCoreAsyncCore to send CancelInvocationMessage when the cancellation token is triggered
  • Uses the same pattern already established for streaming cancellations

Server Changes

  • HubMethodDescriptor: Removed restriction limiting CancellationToken parameters to streaming methods only
  • DefaultHubDispatcher: Regular invocations now register their CancellationTokenSource in ActiveRequestCancellationSources, allowing CancelInvocationMessage to cancel them
  • Logging: Updated log messages to be generic rather than streaming-specific

Tests

  • Added client test verifying CancelInvocationMessage is sent for regular invocations
  • Added server test with a cancelable hub method accepting CancellationToken
  • Updated existing test that previously verified this wasn't supported

Breaking Changes

None. This is purely additive functionality. Existing code continues to work as before.

Notes

As mentioned by @BrennanConroy in #11542 (comment), the server infrastructure was already structured to support this - it just needed to be enabled for regular invocations in addition to streams.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • fakeurl.org
    • Triggering command: /home/REDACTED/work/aspnetcore/aspnetcore/.dotnet/dotnet exec --depsfile /home/REDACTED/work/aspnetcore/aspnetcore/artifacts/bin/Microsoft.AspNetCore.SignalR.Client.Tests/Debug/net10.0/Microsoft.AspNetCore.SignalR.Client.Tests.deps.json --runtimeconfig /home/REDACTED/work/aspnetcore/aspnetcore/artifacts/bin/Microsoft.AspNetCore.SignalR.Client.Tests/Debug/net10.0/Microsoft.AspNetCore.SignalR.Client.Tests.runtimeconfig.json /home/REDACTED/.nuget/packages/xunit.REDACTED.console/2.9.2/tools/netcoreapp2.0/xunit.console.dll /home/REDACTED/work/aspnetcore/aspnetcore/artifacts/bin/Microsoft.AspNetCore.SignalR.Client.Tests/Debug/net10.0/Microsoft.AspNetCore.SignalR.Client.Tests.dll -noautoreporters -xml /home/REDACTED/work/aspnetcore/aspnetcore/artifacts/TestResults/Debug/Microsoft.AspNetCore.SignalR.Client.Tests_net10.0_x64.xml -html /home/REDACTED/work/aspnetcore/aspnetcore/artifacts/TestResults/Debug/Microsoft.AspNetCore.SignalR.Client.Tests_net10.0_x64.html -notrait Quarantined=true -nocolor (dns block)
    • Triggering command: /home/REDACTED/work/aspnetcore/aspnetcore/.dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/aspnetcore/aspnetcore/artifacts/bin/Microsoft.AspNetCore.SignalR.Client.Tests/Debug/net10.0/Microsoft.AspNetCore.SignalR.Client.Tests.runtimeconfig.json --depsfile /home/REDACTED/work/aspnetcore/aspnetcore/artifacts/bin/Microsoft.AspNetCore.SignalR.Client.Tests/Debug/net10.0/Microsoft.AspNetCore.SignalR.Client.Tests.deps.json /home/REDACTED/work/aspnetcore/aspnetcore/artifacts/bin/Microsoft.AspNetCore.SignalR.Client.Tests/Debug/net10.0/testhost.dll --port 43893 --endpoint 127.0.0.1:043893 --role client --parentprocessid 22550 --telemetryoptedin false (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

This section details on the original issue you should resolve

<issue_title>[SignalR] Possibility to cancel long running hub method from client</issue_title>
<issue_description>I´m not quit sure if this post is more of a question or a feature request.

I noticed that the InvokeAsync<TResult>(HubConnection, String, CancellationToken) method accepts a CancellationToken. As far as I understood this token only cancels the invocation (and waiting for a result, ...) on the client, while on the server side the method proceeds.
Is this correct?

If so wouldn´t it be a nice feature to allow such a cancellation? I saw that Google offers this possibility in their gRPC framework aswell:

Cancelling RPCs
Either the client or the server can cancel an RPC at any time. A cancellation terminates the RPC immediately so that no further work is done. It is not an “undo”: changes made before the cancellation will not be rolled back.

When my understanding is wrong please provide me an example on how to do a cancellation of long running hub methods from the client.</issue_description>

<agent_instructions>See comment in #11542 (comment)</agent_instructions>

Comments on the Issue (you are @copilot in this section)

@davidfowl Today we only support cancellation for streams but there's nothing wrong with supporting this for other invocations. @BrennanConroy @anurse I don't think we do support that, but we structured the code in such a way that we could add support for it in the future. @ We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our [Triage Process](https://github.com/dotnet/aspnetcore/blob/master/docs/TriageProcess.md). @davidfowl @muzopraha What's the scenario you have with a long running hub method? @davidfowl @thorgeirk11 No updates, best to add your scenario so we have a record of what people want to use it for before we invest the time. @BrennanConroy File a new issue and show your code. @BrennanConroy CancellationToken in the hub method signature is only supported for Server to client streaming currently.

This issue is tracking adding it for other cases.</comment_new>
<comment_new>@BrennanConroy
Since this feature isn't implemented yet that method signature won't work. It's basically trying to receive a serialized CancellationToken from the client, which isn't going to work.

The cancellation token in InvokeAsync will cancel the client waiting for a server response, but it doesn't pass that info along to the server yet. That's what this issue is tracking adding support for.

public async Task UpdateChannelAsync(TPMChannels channel, CancellationToken cts = default) ->
public async Task UpdateChannelAsync(TPMChannels channel)</comment_new>
<comment_new>@davidfowl
I'll defer to @BrennanConroy here.</comment_new>
<comment_new>@BrennanConroy
Basically we would need to update the client(s) to send a CancelInvocationMessage when the cancellation token passed in to InvokeAsync is canceled.
We currently only send that message type when the client cancels a stream

await SendHubMessage(_state.CurrentConnectionStateUnsynchronized, new CancelInvocationMessage(irq.InvocationId), cancellationToken: default).ConfigureAwait(false);

The server is mostly setup to handle CancelInvocationMessage

case CancelInvocationMessage cancelInvocationMessage:
// Check if there is an associated active stream and cancel it if it exists.
// The cts will be removed when the streaming method completes executing
if (connection.ActiveRequestCancellationSources.TryGetValue(cancelInvocationMessage.InvocationId!, out var cts))
{
Log.CancelStream(_logger, cancelInvocationMessage.InvocationId!);
cts.Cancel();

The logs would likely need to be updated since it assumes streams are the only thing that can be canceled.

We'd also need to update the logic around which hub methods can have a synthetic argument (CancellationToken)

if (IsStreamResponse && p.ParameterType == typeof(CancellationToken))
{
HasSyntheticArguments = true;


A massive stretch goal would be to do the same thing for client results, which would require adding synthetic argument support on the client side and sending CancelInvocationMessage from the server. That work is tracked by #44831 and shouldn't restrict this issue from being worke...

Fixes #11542


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

This comment was marked as outdated.

Copilot AI and others added 3 commits October 17, 2025 19:55
Co-authored-by: BrennanConroy <7574801+BrennanConroy@users.noreply.github.com>
Co-authored-by: BrennanConroy <7574801+BrennanConroy@users.noreply.github.com>
…fying comment

Co-authored-by: BrennanConroy <7574801+BrennanConroy@users.noreply.github.com>
@Copilot Copilot AI changed the title [WIP] Add cancellation capability to long running hub methods Add support for cancelling regular hub invocations from client Oct 17, 2025
@Copilot Copilot AI requested a review from BrennanConroy October 17, 2025 20:11
Copilot finished work on behalf of BrennanConroy October 17, 2025 20:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[SignalR] Possibility to cancel long running hub method from client

2 participants

Morty Proxy This is a proxified and sanitized view of the page, visit original site.