Cancel a long running task over WCF from client

Null Reference picture Null Reference · Mar 10, 2013 · Viewed 8k times · Source

I have a WCF service set to PerCall

I would like to know how I can send a Start call from the client to start a long running process, and send a Cancel command to cancel it

My WCF service looks something like this

 [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

            }

}

I guess the problem here is that, each time a call comes to the server, it's treated as a new request.

So how should starting and cancelling a long running task in WCF be done?

EDIT: I'm hosting it as a windows service

Answer

Stephen Cleary picture Stephen Cleary · Mar 11, 2013

I have a WCF service set to PerCall

... the problem here is that, each time a call comes to the server, it's treated as a new request.

Yup, that's exactly what you're telling it to do. If you can, just change to InstanceContextMode.PerSession; then you can do what you're trying to do (assuming you're self-hosting).

If you can't do this, then you'll have to develop a more complex solution like @PeterRitchie commented. First, your host: IIS is not designed to have long-running operations independent of requests, so I'll assume you're self-hosting. Next, you'll need a form of token (like a GUID) that will act as an identifier for a long-running operation. Your Start method will allocate a GUID and CancellationTokenSource and start the operation, and your Stop method will take a GUID and use that to look up the CancellationTokenSource and cancel the operation. You'll need a shared (static, threadsafe) dictionary to act as lookup.

If your host is IIS, then your solution gets more complex... :)

First, you'll need a backend that's not hosted in IIS. Common choices are an Azure worker role or a Win32 service. Next, you'll need a reliable communications mechanism: an Azure queue, MSMQ, WebSphere, etc. Then you can build your WCF-over-IIS service to have the Start method generate a GUID identifier and drop a message on the queue to start processing. The Stop method takes the GUID and drops a message on the queue to cancel processing. All other logic gets moved to the backend service.