我有一个与外部资源交互的ASP.NET MVC应用程序,并且有一个需要花费大量时间的操作。 所以在控制器中我有这样的方法
[HttpPost]
public async Task<JsonResult> SomeMethod(..., CancellationToken token)
{
await _someService.ExecuteSlowOperationAsync(..., token);
...
}
这种缓慢的操作看起来像
public async Task ExecuteSlowOperationAsync(..., CancellationToken token)
{
return await Task.Run(() =>
{
//interacting with external resource
}, token);
}
此方法与模态视图相关联,如果请求需要花费很长时间,用户可能会决定关闭它。根据我必须取消请求而不等待结果,所以在客户端我有像
的代码...
var request = $.ajax(...);
...
$('#modal').on('hidden.bs.modal', function () {
request.abort();
});
如果我正确地理解了这个article,则取消令牌会通过框架模型绑定器与请求绑定,而不需要对它进行任何操作。当用户关闭模态表单时,在浏览器中我可以看到请求获得状态&#34;取消&#34;但在服务器端缓慢操作仍在执行。我试过
CancellationToken disconnectedToken = Response.ClientDisconnectedToken;
var source = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, disconnectedToken);
然后从这个来源获取令牌,但仍然一无所获。
我觉得我错过了一些重要的事情并对这种情况产生了误解。任何想法如何使它工作?
答案 0 :(得分:0)
我的回答可能有点晚了。但是我想我找到了你的问题。使用Task.Run(Action action, CancellationToken cancellationToken)
取消长时间运行的操作可能并不总是有效。
Using CancellationToken for timeout in Task.Run does not work
如果长时间运行的操作是在您自己的代码中,则应编写如下内容
public async Task ExecuteSlowOperationAsync(..., CancellationToken token)
{
while (true)
{
if(cancelToken.IsCancellationRequested)
{
return;
}
...
}
}
如果您无法修改长时间运行的操作本身的源代码,则可以使用Microsoft.VisualStudio.Threading.ThreadingTools中的WithCancellation
(有关更多信息,请参见https://stackoverflow.com/a/33396646/9483821),您甚至可以在之前使用它。控制器
[HttpPost]
public async Task<JsonResult> SomeMethod(..., CancellationToken token)
{
CancellationToken disconnectedToken = Response.ClientDisconnectedToken;
var linkedToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, disconnectedToken).Token;
await _someService.ExecuteSlowOperationAsync(...).WithCancellation(linkedToken);
...
}