2011-08-31 66 views
2

TASK1:問題有關的任務延續

public Task SendMail(string email) 
{ 
    ... 
} 

TASK2:

public Task<int> SaveToDB(User user) 
{ 
    ... 
} 

我需要做的:

  1. 時TASK1失敗,應該返回一個 「發送失敗」 信息來源;
  2. 當task1成功時,task2開始。
  3. 當task2失敗時,應該返回一個「保存失敗」信息。
  4. 當task2成功時,應該返回一個「保存成功」的信息。

請幫我找到一個解決方案:

public Task<string> SendAndSave(User user){ 
var task1 = SendMail(user.Email); 
var task1Failed = task1.ContinueWith(t => 
{ 
    var e = task1.Exception; 
    return "Send Failed"; 
}, 
TaskContinuationOptions.OnlyOnFaulted | 
TaskContinuationOptions.ExecuteSynchronously); 

var task2 = task1.ContinueWith(t => 
{ 
    var save = SaveToDB(user); 
    try 
    { 
     int result = save.Result; 
     return "Save Succeeded"; 
     } 
    catch(AggregateException ae) 
    { 
      return "Save Failed"; 
     } 
     }, 
     TaskContinuationOptions.NotOnFaulted); 

return Task.Factory.ContinueWhenAny(new[] {task1Failed, task2}, t => t.Result); 
} 

當我運行它,我收到一個錯誤。

我調用它:

var result = SendAndSave(user).Result;

在發生錯誤:

public Task<string> SendAndSave(User user) 
{ 
     ... 
     return Task.Factory.ContinueWhenAny(new[] {task1Failed, task2}, t => t.Result); //Here: A task was cancelled 
} 

調試之後,我有兩個問題:

  • Q1:TASK1後,task1Failed,task2被創建,每個的值爲 CreationOption屬性爲「無」,雖然其狀態爲 「WaitingForActivation」。看來所有的延續選項都是 無效。

  • Q2:對於Task.Factory.ContinueWhenAny的(新[] {task1Failed, TASK2},T => t.Result)的任務,讓我們將其命名爲 「factoryTask」 時, ContinueWhenAny似乎無效。在task1Failed,task2和factoryTask中的每一個的內部 中放置一個斷點後,偶爾會看到 factoryTask中的斷點首先被觸發,儘管在task1Failed或task2完成後應該觸發 。

任何人都可以幫忙嗎?謝謝。

+1

也許你可以先告訴我們,錯誤究竟是什麼? – Carsten

回答

1

儘管我沒有完全理解你的問題,但我理解這裏的問題,基本上你會一直有task1Failed或task2完成但不是兩個,而另一個將被取消! 因此,在WaitOnAny調用中,如果發現其中一個任務已被取消,它將會崩潰,這實際上取決於任務參數的順序,所以在上例中,您首先傳遞task1failed,因此如果此任務已完成ContinueWhenAny工作正常,因爲它檢查的第一個任務已經完成,所以它不檢查另一個,但是如果task1Failed沒有運行,所以它處於取消狀態,ContinueWhenAny會拋出!

爲了避免這種情況,您需要改爲使用TaskCompletetionSource,並且運行的任務將設置該值,然後在最後返回tcs.Task。結果

public Task<string> SendAndSave(User user){ 
var tcs = new TaskCompletionSource<string>(); 
var task1 = SendMail(user.Email); 
var task1Failed = task1.ContinueWith(t => 
{ 
    var e = task1.Exception; 
    tcs.TrySetResult("Send Failed"); 
}, 
TaskContinuationOptions.OnlyOnFaulted | 
TaskContinuationOptions.ExecuteSynchronously); 

var task2 = task1.ContinueWith(t => 
{ 
    var save = SaveToDB(user); 
    try 
    { 
     int result = save.Result; 
     tcs.TrySetResult("Save Succeeded"); 
    } 
    catch(AggregateException ae) 
    { 
     tcs.TrySetResult("Save Failed"); 
    } 
},TaskContinuationOptions.NotOnFaulted); 

return tcs.Task.Result; 
} 
+0

道具給你花時間回答這個問題 – JasonS