3

У меня есть следующий сценарий:Как использовать Task <T> приподняв событие и ожидает событие, чтобы завершить

  1. Клиент, который запрашивает веб-сервиса, чтобы начать

    public bool Start(MyProject project, string error) 
    
  2. Веб-сервис который получает звонок от клиента по методу

    public event EventHandler<StartEventArgs> startEvent; 
    
    public bool Start(MyProject project, string error) 
    { 
        Task<bool> result = StartAsync(project, error); 
    
        return result.Result; 
    } 
    
    protected virtual void OnStart(StartEventArgs e) 
    { 
        // thread safe trick, snapshot of event 
        var se = startEvent; 
        if (se != null) 
        { 
         startEvent(this, e); 
        } 
    } 
    
    private Task<bool> StartAsync(MyProject project, string error) 
    { 
        var taskCompletion = new TaskCompletionSource<bool>(); 
    
        this.startEvent += (p, e) => taskCompletion.TrySetResult((e.Error == string.Empty) ? true : false); 
    
        this.OnStart(new StartEventArgs(project, error)); 
    
        return taskCompletion.Task; 
    } 
    
  3. Приложение, которое подписывается на событие, которое находится в веб-службы:

    app.Start += EventHandler(App_Start) 
    
    private bool App_Start() 
    { 
        // does something 
        returns true/false 
    } 
    
  4. Я хочу веб-службы, чтобы выпалить событие в задаче, а затем ждать функции в App.exe к затем вернитесь, чтобы уведомить пользователя о том, что задача выполнена успешно.

Я не знаю, как это сделать, но в теории это будет выглядеть примерно так:

Task<bool> startTask = Task.Factory.StartNew(() => { OnStart() }); 
startTask.WaitAll(); // I think this is what I would need to for 4.0 
return startTask.Result 

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

Возможно ли это, или я ошибаюсь с этим?

Обновление: Очевидно, что OnStart не является событием, так как мне делать то, что вы пытаетесь мне объяснить?

ответ

1

Вы можете обернуть событие, описывающее асинхронный шаблон, основанный на событии, в Task<T> через TaskCompletionSource<T>. Основной узор, как правило, что-то вроде:

Task<bool> StartAsync() 
{ 
    var tcs = new TaskCompletionSource<bool>(); 

    // When the event returns, set the result, which "completes" the task 
    service.OnStarted += (o,e) => tcs.TrySetResult(e.Success); 

    // If an error occurs, error out the task (optional) 
    service.OnStartError += (o,e) => tcs.TrySetException(e.Exception); 

    // Start the service call 
    service.Start(); 

    // Return the Task<T> 
    return tcs.Task; 
} 
+0

Является ли код выше на стороне App.exe для этого сценария? – ShaffDaddy

+0

Nevermind, я просто понял (или так, я думаю, что сделал), где это должно быть :) – ShaffDaddy

+0

Я собираюсь изменить свой код, чтобы вы могли видеть, что я пытаюсь сделать, я все еще немного смущен тем, как использовать TaskCompletionSource – ShaffDaddy

0

Так что я думаю, что я сейчас понимание того, как это должно быть сделано здесь, как я делаю это сейчас. Код

Услуги:

public void SetStartTask(Task<bool> startTask) 
     { 
      this.startTask = startTask; 
     } 

public bool Start(RtProjectInfo project, string error) 
     { 
      StartEventArgs args = new StartEventArgs(project, error); 

      OnStart(args); 

      return startTask.Result; 
     } 

protected virtual void OnStart(StartEventArgs e) 
     { 
      // thread safe trick, snapshot of event 
      var se = startEvent; 

      if (se != null) 
      { 
       startEvent(this, e); 
      } 
     } 

public void StartFinished(MyProject project, string error) 
     { 
      OnStartFinish(new StartEventArgs(project, error)); 
     } 

protected virtual void OnStartFinish(StartEventArgs e) 
      { 
       var sef = startFinished; 

       if (sef != null) 
       { 
        startFinished(this, e); 
       } 
      } 

Вот это реализация тестового клиента

public void Start_Event(object sender, StartEventArgs e) 
     { 
      Task<bool> startTask = StartAsync(); 

      service.SetStartTask(startTask); 

      DoOtherWork(); 
      DoOtherWork(); 
      DoOtherWork(); 
     } 

private Task<bool> StartAsync() 
     { 
      var taskCompletion = new TaskCompletionSource<bool>(); 

      service.startFinished += (p, e) => 
      { 
       taskCompletion.TrySetResult((e.Error == string.Empty) ? true : false); 
      }; 

      return taskCompletion.Task; 
     } 

private void DoingWork() 
     { 
      for(int i = 0; i < 100; ++i) 
      { 

      } 

      service.StartFinished(project, error); 
     } 

     private void DoOtherWork() 
     { 
      for (int i = 0; i < 100000; ++i) 
      {      
      } 
     } 

Так, очевидно, всякий раз, когда кто-то звонит клиент DoingWork() событие будет получено, и все довольны! Если у кого-то есть предложения, которые лучше, укажите их, поскольку я просто изучаю, как правильно использовать TPL.

+0

@Reed Copsey, спасибо за указание, как это делается. – ShaffDaddy

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