[英]How to cancel an async WCF call?
我一直在尝试一些时间,以了解如何基于新的.NET 4.5 CancellationToken机制实现WCF呼叫取消。 我发现的所有样本都不基于WCF,并且没有跨越服务边界。
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class MyService : IMyService
{
public void LongOperation()
{
// do stuff that takes ages...
// please cancel me!
}
}
使用自动生成的代理:
private async void DoLongRunningTaskAsync()
{
var asyncTask = _myService.LongOperationAsync();
await asyncTask;
}
如何取消此任务? 请提供适用于.NET 4.5+上WCF的具体示例
以下答案似乎表明,由于技术原因,这是不可能的。 因此,想象一下,我将服务设置为ContextMode=Session
,然后设置一个静态变量(在单独的服务调用中)称为cancellationPending=true
,我的原始调用在此阶段仍在运行,并且会定期检查该变量。 我仍然无法取消吗? 还是不可能吗? 如果是这样,为什么?
如前所述。 跨越服务边界并在服务器端取消是不可能的。
如果要在客户端取消任务,则可以使用Microsoft.VisualStudio.Threading.ThreadingTools的扩展方法WithCancellation
它是Visual Studio SDK的一部分,或者您也可以从Nuget获取它。
CancellationTokenSource ct = new CancellationTokenSource();
ct.CancelAfter(20000);
var asyncTask = _myService.LongOperationAsync();
await asyncTask.WithCancellation(ct.Token);
用两个词来说-这是不可能的。
如果您了解WCF调用的本质,那么它将变得显而易见。
看您的示例,我们通常会看到:通过网络连接的两台单独的机器A和B。 在机器A上,您有一些侦听套接字的组件,当它收到命令时,它将启动同步长计算RemoteCall()
。
在计算机B上,您有一个实际上具有两个自动生成方法的客户端
BeginRemoteCall->IAsyncResult
+ EndRemoteCall(IAsyncResult)
。
本质上,新的基于任务的异步调用版本(aka RemoteCallAsync()->Task
)完全相同,并且您始终可以使用TaskFactory.FromAsync(BeginRemoteCall,EndRemoteCall)->Task
创建自己的任务
当您在客户端上调用BeginRemoteCall
时,将命令发送到第二台计算机“请开始计算”,然后添加一个回调,在完成计算并得出结果时将调用该回调。 在内部,此异步实现使用I / O完成端口,并允许您的客户端处于非阻塞状态。
但是,如果已经开始,则无法取消服务器端的操作。 您可能对结果不感兴趣,可以忽略回调,但是无论如何,服务器端的计算将完成。
而已
编辑问题后,我看到取消逻辑级别是可以接受的。 如果是这样,可以尝试以下算法。
1)使用InstanceContextMode=InstanceContextMode.PerSession
创建服务,这样可以保证您具有用于服务后续请求的相同服务实例。
2)要启动新会话,请使用标有OperationContract(IsInitiating = True)
服务操作
3)创建为服务成员。 不是静态的。 这将是服务状态
CancellationTokenSource ct = new CancellationTokenSource();
4)在每种服务方法内部,您将必须在任务内部开始新的计算并将取消令牌作为此任务的参数。
[ServiceContract(SessionMode = SessionMode.Allowed)]
public interface ICalculator
{
[OperationContract(IsInitiating = True)]
Bool Begin()
[OperationContract(IsInitiating = false)]
double Add(double n1, double n2)
}
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)]
public class CalculatorService : ICalculator
{
CancellationTokenSource cts = new CancellationTokenSource();
public double Add(double n1, double n2)
{
var cancellationToken = cts.Token;
var t = Task<double>.Factory.StartNew(() => {
// here you can do something long
while(true){
// and periodically check if task should be cancelled or not
if(cancellationToken.IsCancellationRequested)
throw new OperationCanceledException();
// or same in different words
cancellationToken.ThrowIfCancellationRequested();
}
return n1 + n2;
}, cancellationToken);
return t.Result;
}
public Bool Begin(){}
}
所有示例均来自我的脑海,尚未尝试过是否真的有效。 但是您可以尝试。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.