繁体   English   中英

如何取消异步WCF调用?

[英]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(){}
}

这是 WCF会话的快速描述

所有示例均来自我的脑海,尚未尝试过是否真的有效。 但是您可以尝试。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM