取消来自客户端的WCF长时间运行任务

6

我有一个WCF服务,设置为PerCall。

我想知道如何从客户端发送“启动”调用以启动长时间运行的过程,并发送“取消”命令以取消它。

我的WCF服务看起来像这样

 [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    public class Service1 : IService1
    {

        CancellationTokenSource cancelToken = new CancellationTokenSource();



        public void Start()
        {

            var compute = Task.Factory.StartNew(StartLongRunningTask, cancelToken.Token);
        }

        public void Stop()
        {

            cancelToken.Cancel();
        }

            private void StartLongRunningTask()
            {
                  //process here

            }

}

我想问题在于每次调用服务器时,它都被视为新的请求。

那么如何在WCF中启动和取消长时间运行的任务呢?

编辑:我将其作为Windows服务托管。


1
你需要在WCF类之外存储令牌。主机在WCF请求之间可能会重新启动,这取决于主机;因此,您可能需要先处理这个问题。您可能需要某种其他令牌来查找传递给Stop合同的取消令牌源。 - Peter Ritchie
当你说在WCF类之外时,是指创建另一个dll来处理令牌,并通过WCF项目引用该dll吗?这样做不还是一样吗? - Null Reference
2个回答

5
我有一个WCF服务设置为PerCall,问题在于每当有请求到达服务器时,都会被视为一个新的请求。如果可以,请将其更改为InstanceContextMode.PerSession,这样您就可以实现您想要做的事情(假设您是自托管的)。如果无法这样做,则必须开发更复杂的解决方案,如@PeterRitchie所评论的那样。首先,您的主机:IIS不适合独立于请求之外具有长时间运行的操作,因此我将假定您是自托管的。接下来,您需要一种类似于GUID的令牌,用作长时间运行操作的标识符。您的“Start”方法将分配一个GUID和CancellationTokenSource并启动操作,而您的“Stop”方法将获取GUID并使用它来查找CancellationTokenSource并取消操作。您将需要一个共享的(静态的、线程安全的)字典作为查找。如果您的主机是IIS,则您的解决方案变得更加复杂... :)首先,您需要一个不在IIS中托管的后端。常见选择是Azure worker角色或Win32服务。接下来,您需要一个可靠的通信机制:Azure队列、MSMQ、WebSphere等。然后,您可以构建支持WCF-over-IIS的服务来生成GUID标识符,并将消息放在队列上以开始处理。Stop方法获取GUID并将其放在队列上以取消处理。所有其他逻辑都被移动到后端服务中。

是的,我的服务托管在 Windows 服务上。 - Null Reference
所以,我需要一个带有[ThreadStatic]属性的静态字典,用于存储GUID和取消对象,并在客户端下次发送调用时从字典中提取它? - Null Reference
1
ThreadStatic 不起作用。无法保证取消调用将在服务器上作为原始调用线程的相同线程运行。Stephen 提到了并发字典。但是,如果你从头到尾使用 .net 4.5,我强烈建议你看看我的解决方案(它被投票降低了)。 - Aron
2
@Aron 是正确的。我指的是一个 static ConcurrentDictionary<Guid, CancellationTokenSource> - Stephen Cleary

2
根据您的询问,客户似乎已经意识到了请求的异步性质。@StephenCleary和@PeterRitchie的观点非常好,但您的第一步是重新设计您的服务/合同,以正确实现异步服务,并添加一些信息/句柄来与客户端进行通信,以便处理长时间运行的操作。
框架包含多个异步编程范例(已经 :-)),但是当涉及到WCF时,您需要参考如何:实现异步服务操作
这将提供一些基础设施,但不一定具备自动取消操作的能力。严格来说,关于取消(因为这是您的问题),您将不得不扩展任何解决方案以支持取消。至少,您需要向服务“工作人员”添加必要的逻辑来监视并尊重取消令牌。
你可能会遇到的其他考虑因素:取消后返回结果;取消已经完成的任务(如果在取消请求到来之前你已经更新了100万条记录怎么办);异常处理(使用基于任务的编程时,异常不会被抛出,而是捆绑在任务中,或者其他描述正在进行操作的“载体”中)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接