I have an ASP.NET MVC application that interacts with external resources and there is an operation which takes a lot of time. So in controller I have method like this
[HttpPost]
public async Task<JsonResult> SomeMethod(..., CancellationToken token)
{
await _someService.ExecuteSlowOperationAsync(..., token);
...
}
And this slow operation looks like
public async Task ExecuteSlowOperationAsync(..., CancellationToken token)
{
return await Task.Run(() =>
{
//interacting with external resource
}, token);
}
This method linked with modal view and if request will take so much time user might decide to close it. According to that I have to cancel request without awaiting results, so on client-side I have code like
...
var request = $.ajax(...);
...
$('#modal').on('hidden.bs.modal', function () {
request.abort();
});
If I understood this article correctly, cancellation token binds with request via framework model binder and no need to do something with it. When user close modal form, in browser concole I can see that request gets status "canceled" but on server-side slow operation is still executing. Aslo I tried with
CancellationToken disconnectedToken = Response.ClientDisconnectedToken;
var source = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, disconnectedToken);
and then took token from this source, but still got nothing.
I feel like I'm missing some important thing and have misunderstanding of this situation. Any ideas how to make it work?
I am probably a little late with my answer. But I think I found your problem. Using Task.Run(Action action, CancellationToken cancellationToken)
to cancel your long running operation might not always work.
Using CancellationToken for timeout in Task.Run does not work
If the long running operation is in your own code, you should write something like this
public async Task ExecuteSlowOperationAsync(..., CancellationToken token)
{
while (true)
{
if(cancelToken.IsCancellationRequested)
{
return;
}
...
}
}
If you cannot modify the source code of the long running operation itself, you can use WithCancellation
from Microsoft.VisualStudio.Threading.ThreadingTools (see https://stackoverflow.com/a/33396646/9483821 for more info) which you even could use earlier at your controller
[HttpPost]
public async Task<JsonResult> SomeMethod(..., CancellationToken token)
{
CancellationToken disconnectedToken = Response.ClientDisconnectedToken;
var linkedToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, disconnectedToken).Token;
await _someService.ExecuteSlowOperationAsync(...).WithCancellation(linkedToken);
...
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With