Open ddweber opened 5 years ago
Today we only support cancellation for streams but there's nothing wrong with supporting this for other invocations.
I believe we support it for non-streaming as well... As long as you accept a CancellationToken
in your Hub method, we'll automatically flow it forward. For example, the below should work:
// Server
public async Task LongRunningOperationAsync(string foo, int bar, CancellationToken cancellationToken)
{
}
// Client
var result = await connection.InvokeAsync("foo", 42, someCancellationToken);
If it doesn't, let us know!
@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.
Ah yes, I believe the server supports it but the client does not. Moving to the backlog to add this support.
I'm not really a SignalR user, just inherited a project that uses it, but can I make a suggestion? If you're going to support cancellation of an in-flight request, instead of rolling your own "token", just take an AbortSignal. This is what the Fetch API already uses, so if you're using Fetch under the hood, it's as simple as passing the signal
argument through.
instead of rolling your own "token", just take an AbortSignal.
That's for JavaScript though. This issue is discussing the .NET Client, where CancellationToken is the equivalent primitive.
If you're looking for changes to JavaScript cancellation (I don't think we support cancellation of server methods in JS at all right now, so it's certainly a good discussion to have!) then I'd suggest filing a new issue.
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.
Hi, we need this functionality too. We have been waiting for this feature several months and one of our motivations for upgrading to .NET5 was this feature which was presented in .NET5 backlog. Now I see, it is not implemented yet :/ Is there any ETA for this one? Thank you.
@muzopraha What's the scenario you have with a long running hub method?
Sorry to hijack the issue but I'd also like to report one possible scenario.
Our company uses SignalR as a signal server for WebRTC. There are 3 main actors involved: caller, signaling server and a callee. There's a method the caller calls to initiate a call and notify the callee. Ideally, method would wait for the callee to answer and return the information required for the call to be established. There is a problem, however: if the caller decides to cancel a call there's no way for us to cancel the initialization method. Due to this issue, currently we immediately return from the initialization method and use another server->client callback to inform of the result and one more client->server method to inform the signaling server if the caller has cancelled the call. If we had a way for the caller to cancel the initialization method it would remove the need of those two additional methods.
@muzopraha What's the scenario you have with a long running hub method? @davidfowl The scenario is, that our clients can run async heavy-weight server side operations (gathering data from other services) via SignalR. These clients waits for results (listen to SignalR), but it is quite common that these clients need to stop processing these requests. Now, we are cancelling these async operations via cancellation token on client side, but server-side is still running even if it is not necessary. Our solution architecture is like this: Clients (WPF/Blazor/etc) => WebAPI => Application => DB
@davidfowl Any updates on this?
@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.
If you're collecting use cases, I can briefly describe mine.
I load data to show on a map, from a variety of sources. One provides records via SignalR. If the user drags the map, I can start loading new records for the area that has just scrolled into view. If they drag it again before the network request has finished, I may no longer need those records, so I can cancel the in-flight request. With Fetch / AbortSignal, this process is very simple and works perfectly.
@thw0rted your use case sounds like it could use SignalR streaming to stream a list of records matching the new viewport. I have somewhat similar use case and streaming worked well for me.
Thanks for the link @secretwpn , that's basically exactly what I had in mind. In fact, the API maps almost exactly to the RxJS Observable pattern which I already use extensively. Of course, I'm only consuming somebody else's back end API so I'm not sure that the stream
method is available for the service I use, but I will make a note to come back and look into it when I have time.
@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.
We also need this functionality. User starts some long runing process on server and waiting to get data. He has option to cancel this process on Client side. But, unfortunately, this cancelation means nothing on Server side. As result user can star-stop N times this process. And all these N processes will be running on server side until they will be finished.
From our point of view cancelation is quite important functionality. Especially if take in account that implemented interfaces assume it should work (i.e. presence of CancelationToken). It took some time for us to figure out that it does not work.
Please implement this ticket. Thank you.
According to the docs this should be possible.
However, this doesn't seem to work in my tests. Calling the dispose method on ISubscription stops the stream client-side, but the server continues to stream events.
Our use-case is streaming a file download from server to client. The client should be able to cancel the download and stop the file chunks from being sent from the server.
File a new issue and show your code.
Actually this issue might just relate to how Chrome dev tools does network throttling, which is how we're testing. With network throttling on there seems to be a buffer of events which continues to be sent even after dispose is called. The stream is actually being cancelled on the server. So probably no issue in the real world.
// Server public async Task LongRunningOperationAsync(string foo, int bar, CancellationToken cancellationToken) { } // Client var result = await connection.InvokeAsync("foo", 42, someCancellationToken);
It doesn't work for me.
First of all, it looks like client side call in your example missing a first parameter which is a called method name ("LongRunningOperationAsync").
And even with a proper first parameter it still doesn't work. It works only when I remove cancellationToken parameter from the server side method declaration.
The issue looks the same as this.
Is there some attribute that could help?
I'm using 3.1.23, can't go higher than Core 3.1
CancellationToken in the hub method signature is only supported for Server to client streaming currently.
This issue is tracking adding it for other cases.
@davidfowl Any updates on this?
any update?
Any update on this?
It's an accepted overload, just confusing to as why the hub method would not be able to capture this?
InvokeAsync:
public static Task
Description I am experiencing an issue with SignalR's InvokeAsync method in a Blazor WebAssembly application. The problem arises when invoking a server-side Hub method with what seems like the correct number and types of parameters, yet I receive an error indicating a mismatch.
Environment Framework: Blazor WebAssembly SignalR Version: 8.0.0 .NET Version: 8.0.0
Error Message: dbug: Microsoft.AspNetCore.SignalR.Internal.DefaultHubDispatcher[22] Parameters to hub method 'UpdateChannelAsync' are incorrect. System.IO.InvalidDataException: Invocation provides 1 argument(s) but target expects 2.
Client Side:
public async Task CreateOrUpdateChannelAsync(ChannelsViewModel channel, CancellationToken cts)
{
// [Include relevant client-side code, focusing on the invocation part]
_signalRConnectionService.HubConnection.InvokeAsync
Server-Side Hub Method:
public async Task
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)
@davidfowl if this is something the team would be interested in supporting, let us know. If you could give us an idea of the implementation you'd prefer we can band together to make progress here.
I'll defer to @BrennanConroy here.
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
https://github.com/dotnet/aspnetcore/blob/54c0cc8fa74e8196a2ce0711a20959143be7fb6f/src/SignalR/clients/csharp/Client.Core/src/HubConnection.cs#L708
The server is mostly setup to handle CancelInvocationMessage
https://github.com/dotnet/aspnetcore/blob/54c0cc8fa74e8196a2ce0711a20959143be7fb6f/src/SignalR/server/Core/src/Internal/DefaultHubDispatcher.cs#L183-L189
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
)
https://github.com/dotnet/aspnetcore/blob/54c0cc8fa74e8196a2ce0711a20959143be7fb6f/src/SignalR/server/Core/src/Internal/HubMethodDescriptor.cs#L64-L66
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 https://github.com/dotnet/aspnetcore/issues/44831 and shouldn't restrict this issue from being worked on.
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 aCancellationToken
. 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:
When my understanding is wrong please provide me an example on how to do a cancellation of long running hub methods from the client.