【问题标题】:Cancel a long running task over WCF from client从客户端取消通过 WCF 长时间运行的任务
【发布时间】:2013-03-10 17:06:14
【问题描述】:

我将 WCF 服务设置为 PerCall

我想知道如何从客户端发送 Start 调用来启动一个长时间运行的进程,并发送 Cancel 命令来取消它

我的 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 服务托管

【问题讨论】:

  • 您必须将令牌存储在 WCF 类之外。主机可以在 WCF 请求之间重新启动,具体取决于主机;所以,你可能必须先处理这个问题。您可能必须拥有某种其他代币来查找您传递给 Stop 合约的取消代币来源。
  • 当您说在 WCF 类之外时,您的意思是创建另一个 dll 来处理令牌,并由 WCF 项目引用这个 dll 吗?不会还是一样吧?

标签: c# .net wcf nettcpbinding long-running-processes


【解决方案1】:

我将 WCF 服务设置为 PerCall

...这里的问题是,每次调用到达服务器时,它都会被视为一个新请求。

是的,这正是您要它做的事情。如果可以的话,改成InstanceContextMode.PerSession;那么你可以做你想做的事(假设你是自托管的)。

如果你不能做到这一点,那么你将不得不像@PeterRitchie 评论的那样开发一个更复杂的解决方案。首先,您的主机:IIS 并非设计为独立于请求进行长时间运行的操作,因此我假设您是自托管的。接下来,您需要一种形式的令牌(如 GUID),它将充当长时间运行操作的标识符。您的 Start 方法将分配一个 GUID 和 CancellationTokenSource 并开始操作,而您的 Stop 方法将采用一个 GUID 并使用它来查找 CancellationTokenSource 并取消操作。您需要一个共享的(静态的、线程安全的)字典来充当查找。

如果您的主机 IIS,那么您的解决方案会变得更复杂... :)

首先,您需要一个不在 IIS 中托管的后端。常见的选择是 Azure 辅助角色或 Win32 服务。接下来,您将需要一个可靠的通信机制:Azure 队列、MSMQ、WebSphere 等。然后您可以构建 WCF-over-IIS 服务,让 Start 方法生成 GUID 标识符并将消息放入队列开始处理。 Stop 方法采用 GUID 并将消息放在队列中以取消处理。所有其他逻辑都移至后端服务。

【讨论】:

  • 是的,我的服务托管在 Windows 服务中
  • 那么,我需要一个带有 [ThreadStatic] 属性的静态字典,它存储一个 guid 和取消对象,并在客户端下次发送呼叫时将其从字典中拉出?
  • ThreadStatic 不起作用。无法保证取消调用将在服务器上作为与原始调用线程相同的线程运行。 Stephen 指的是并发字典。但是,如果您端到端使用 .net 4.5,我认真建议您查看我的解决方案(被否决)。
  • @Aron 是正确的。我的意思是static ConcurrentDictionary<Guid, CancellationTokenSource>
【解决方案2】:

根据您的询问方式,客户端似乎知道请求的异步性质。

@StephenCleary 和@PeterRitchie 的观点非常好,但您的第一步是重新执行您的服务/合同以正确实施异步服务,并添加将一些信息/句柄回传(给客户端)以长期运行的方式操作。

该框架包含多个异步编程范例(已经 :-))但是当涉及到 WCF 时,您有点回退到 How to: Implement an Asynchronous Service Operation

这将提供一些基础设施,但不一定能够自动取消操作。

严格谈论取消(因为这是您的问题):您将不得不扩展您的解决方案最终要取消的任何内容。至少你需要为你的服务“worker”添加必要的逻辑来监控和兑现取消令牌。

您可能会遇到的其他注意事项:取消返回结果;取消已成功完成的任务(在取消请求到来时,你们更新了 1,000,000 条记录);异常处理(基于任务的编程异常不会被抛出,而是捆绑在 Task 或您用来描述正在进行的操作的任何其他“车辆”中)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-25
    • 1970-01-01
    相关资源
    最近更新 更多