我一直在尝试基于新的.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
的静态变量(在一个单独的服务调用中),我的原始调用仍在此阶段运行,并定期检查该变量。我还是不能取消吗?它还不可能吗?如果是这样,为什么?
答案 0 :(得分:3)
如前所述。在服务器端跨越服务边界并取消是不可能的。
如果您想在客户端取消任务,可以使用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);
答案 1 :(得分:3)
用两个词来说 - 这是不可能的。
如果您了解WCF的性质,那就很明显了。
看看你的例子,我们通常看到的是:
两个独立的机器A和B,通过网络连接。
在机器A上,你有一些监听套接字的组件,当它获得一个命令时,它会启动同步长计算RemoteCall()
。
在机器B上你有一个客户端,其实际上有两个自动生成的方法
BeginRemoteCall->IAsyncResult
+ EndRemoteCall(IAsyncResult)
。
基于新任务的异步调用版本(又名RemoteCallAsync()->Task
)本质上完全相同,您始终可以使用TaskFactory.FromAsync(BeginRemoteCall,EndRemoteCall)->Task
创建自己的任务
当你在客户端上调用BeginRemoteCall
时,你将命令发送到第二台机器"请开始计算",然后你添加一个回调,
当计算完成并得出结果时,将调用它。在内部,此异步实现使用I / O完成端口,并允许您的客户端无阻塞。
但如果已经启动,则无法取消服务器端的操作。您可能对结果不感兴趣,可能会忽略您的回调,但无论如何都会完成服务器端的计算。
那是
答案 2 :(得分:1)
在编辑问题后,我发现取消逻辑电平是可以接受的。如果是这样,可以尝试以下算法。
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(){}
}
Here is a quick descriptions个WCF会话。
所有的例子都是我的头脑,如果确实有效的话还没试过。但你可以试试。