如何取消异步WCF调用?

时间:2015-10-28 15:32:41

标签: c# wcf asynchronous service cancellationtokensource

我一直在尝试基于新的.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的静态变量(在一个单独的服务调用中),我的原始调用仍在此阶段运行,并定期检查该变量。我还是不能取消吗?它还不可能吗?如果是这样,为什么?

3 个答案:

答案 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会话。

所有的例子都是我的头脑,如果确实有效的话还没试过。但你可以试试。