问题
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
回答1:
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.
回答2:
From how you've asked, the client seems to be aware of the async nature of the request.
@StephenCleary and @PeterRitchie's points are excellent, but your first step is to re-do your service/contract to properly implement an async service and add the means of communicating back (to client) some information/handle to the long running operation.
The Framework contains several paradigms for asynchronous programming (already :-) )but when it comes to WCF, you kinda fall back to How to: Implement an Asynchronous Service Operation
That will provide some infrastructure, but not necessarily the ability to automatically cancel an operation.
Speaking strictly about the cancellation (as this is your question): you will have to extend whatever your solution ends up being for cancellation. At the minimum you need to add necessary logic to your service “worker” to monitor and honor the cancellation token.
Other considerations that you may expect to encounter: return result from cancellation; cancelling a task that has managed to complete (what of you updated the 1,000,000 records by the time the cancellation request came); exception handling (with task-based programming exceptions are not thrown, but bundled in the Task, or whatever other “vehicle” you use to describe the ongoing operation).
来源:https://stackoverflow.com/questions/15324995/cancel-a-long-running-task-over-wcf-from-client