2015-10-28 5 views
2

Я пытался выяснить, как реализовать отмену вызова WCF на основе нового механизма .NET 4.5 CancellationToken. Все найденные мной образцы не основаны на WCF и не пересекают границу сервиса.Как отменить вызов async WCF?

Моя служба:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)] 
public class MyService : IMyService 
{ 
    public void LongOperation() 
    { 
     // do stuff that takes ages... 
     // please cancel me! 
    } 
} 

Мой клиент (Desktop App):

Использование автоматического сгенерированные прокси:

private async void DoLongRunningTaskAsync() 
{ 
    var asyncTask = _myService.LongOperationAsync(); 
    await asyncTask; 
} 

Как отменить эту задачу? Просьба представить конкретный пример, применимый к ФОС на .NET 4.5+

EDIT:

ответы ниже, кажется, указывают, что его невозможно по техническим причинам. Итак, представьте, я делаю свою услугу ContextMode=Session, затем устанавливаю статическую переменную (в отдельном вызове службы) под названием cancellationPending=true, мой первоначальный вызов все еще работает на этом этапе и периодически проверяет эту переменную. Неужели я все еще не смогу отменить? было бы все еще невозможно? если да, то почему?

+0

Ответил здесь, я думаю: https://stackoverflow.com/questions/3039323/whats-the-best-way-to-cancel-an-asynchronous-wcf-request –

+0

Согласен, ответил там. Я написал ниже довольно то же самое, но с большим количеством слов. – Mimas

+0

Ваше решение в редактировании выглядит нормально. Вы можете попробовать проверить, работает ли он в прототипе. Мой ответ основывался на предположении, что после его запуска (если вы используете wcf с привязкой к сети) невозможно остановить HTTP-вызов с клиентской стороны. Как только запрос ушел, он исчез. Поэтому я не вижу возможности, как WCF может получить это ограничение с помощью одного вызова. Но, как вы описали, с двумя независимыми вызовами и общей переменной на стороне сервера она может работать. Я сомневаюсь, что это реализовано nativly. Но я честно не знаю. – Fabian

ответ

2

Как указано ранее. Невозможно пересечь границу обслуживания и отменить на стороне сервера.

Если вы хотите, чтобы отменить задание на стороне клиента, вы можете использовать метод расширения WithCancellationMicrosoft.VisualStudio.Threading.ThreadingTools от

Это часть Visual Studio SDK или вы также можете получить его от Nuget.

CancellationTokenSource ct = new CancellationTokenSource(); 
ct.CancelAfter(20000); 
var asyncTask = _myService.LongOperationAsync(); 
await asyncTask.WithCancellation(ct.Token); 
+0

Спасибо, см. Мое редактирование. – sprocket12

3

В двух словах - это невозможно.

Если вы понимаете, какой вызов WCF по своей природе, это становится очевидным.

Посмотрите на свой пример, что мы видим в целом: Две отдельные машины A и B, подключенные через сети. На машине A есть компонент, который прослушивает сокет, и когда он получает команду, он запускает синхронные длинные вычисления RemoteCall().

На машине В вас есть клиент, который имеет два автогенерируемые методы в самом деле

BeginRemoteCall->IAsyncResult + EndRemoteCall(IAsyncResult).

Новая задача на основе версии асинхронного вызова (ака RemoteCallAsync()->Task) по своей природе абсолютно то же самое, и вы всегда можете создать свою собственную задачу, используя TaskFactory.FromAsync(BeginRemoteCall,EndRemoteCall)->Task

При вызове BeginRemoteCall на клиенте, вы посылаете команду вторая машина «пожалуйста, начните вычисление», а затем добавьте обратный вызов, , который будет вызываться, когда расчет будет выполнен, и придут результаты. Внутри этой асинхронной реализации используются порты завершения ввода-вывода и позволяет вашему клиенту быть неблокирующимся.

Но не существует способа отменить операцию на стороне сервера, если она уже запущена. Вы можете не интересоваться результатами, вы можете игнорировать ваш обратный вызов, но вычисления на стороне сервера все равно будут завершены.

Вот это

+0

Спасибо, см. Мое редактирование. – sprocket12

0

После редактирования вопроса я вижу, что это приемлемо иметь отмену логического уровня. Если это так, можно попробовать следующий алгоритм.

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

Here is a quick descriptions заседаний WCF.

Все примеры только с моей головы, не пробовали, если они действительно работают. Но вы можете попробовать.

Смежные вопросы