2014-07-20 57 views
0

我正在嘗試使用Reactive Extensions創建一個REST API調用的協調序列來提供一些數據的服務層。爲了這個問題,我使用了可觀察的Octokit.net庫來試圖從GitHub的REST API中抽取一些數據(請不要選擇Octokit庫的方式來使用它)。具體來說,我想要檢索用戶的詳細信息,存儲庫列表和ssh密鑰列表。所以我想協調下面的操作順序:使用Reactive Extensions(Rx)協調異步REST API調用序列

a。通過呼叫用戶api b帶來用戶詳細信息。當結果出現時,將用戶登錄並並行啓動兩個REST調用以檢索repos列表和ssh密鑰列表。 c。當兩個API呼叫回購和ssh密鑰完成時,在結果序列中生成一個項目(GithubUserDTO),其中包含a)和b)的API結果填充的字段。以下是我迄今爲止生成的代碼,其中似乎受到Zip的影響。

public IObservable<GithubUserDto> Get(string username) 
    { 
     return githubObservableClient.User.Get(username) 
      .SelectMany(user => 
      { 
       var userRepos = githubObservableClient.Repository.GetAllForUser(user.Login /* for the sake of demo, I assume I don't have user.Login from beginning */); 
       var sshKeys = githubObservableClient.SshKey.GetAll(user.Login /* for the sake of demo, I assume I don't have user.Login from beginning */); 

       return userRepos.Zip(sshKeys, (repo, sshkey) => 
       { 
        var userDto = new GithubUserDto() {Id = user.Id, Name = user.Name}; 
        userDto.Repositories.Add(repo.FullName); 
        userDto.SshKeys.Add(sshkey.Key.Substring(0, Math.Min(20, sshkey.Key.Length))); 
        return userDto; 
       }); 
      }); 
    } 

凡GithubUserDto樣子:

public class GithubUserDto 
    { 
     public GithubUserDto() 
     { 
      Repositories = new List<string>(); 
      SshKeys = new List<string>(); 
     } 

     public int Id { get; set; } 
     public string Name { get; set; } 
     public List<string> Repositories { get; set; } 
     public List<string> SshKeys { get; set; } 
    } 

1)我怎樣才能確保在GithubUserDto序列中的項目將在API調用存儲庫和SSHKEY將獨立,在異步模式下完成生產? Zip似乎不是這種情況下的選項。

2)即使對「次級」API之一(如SshKey)的調用失敗(例如,由於網絡問題),如何在結果序列中繼續生成GithubUserDto項?

回答

0

它看起來像SshKeys和存儲庫一次返回一個,但你真正需要的是一個列表。您可以通過在Observable上使用ToListIObservable<T>獲得IObservable<IList<T>>

但在你這樣做之前,你會想要處理錯誤情況。如果您只是想忽略異常,則可以使用接受ObservableCatch運算符的超載。您可以將Empty observable傳遞給該運算符,並且當發生異常時,它將忽略它並切換到空觀察值而不是原始源。

public IObservable<GithubUserDto> Get(string username) 
{ 
    return githubObservableClient.User.Get(username) 
     .SelectMany(user => 
     { 
      var userRepos = githubObservableClient.Repository 
       .GetAllForUser(user.Login) 
       .Catch(Observable.Empty<Repository>()) // empty if error 
       .ToList(); // Put all Repositories into a list 

      var sshKeys = githubObservableClient.SshKey 
       .GetAll(user.Login) 
       .Catch(Observable.Empty<SshKey>()) // empty if error 
       .ToList(); // Put all Repositories into a list 

      return Observable.Zip(
       userRepos, 
       sshKeys, 
       (repos, keys) => 
       { 
        return new GithubUserDto() { 
         Id    = user.Id, 
         Name   = user.Name, 
         Repositories = repos, 
         SshKeys   = keys 
        }; 
       } 
      ); 
     }); 
} 
+0

謝謝。如果其中一個電話是一個等待任務呢?例如,如果sshkeys調用是通過HttpClient.GetAsync完成的?異常處理是如何處理的? –

+0

如果任務發生錯誤,await會拋出一個異常,所以你可以試着繞​​過它。或者,如果你願意,你可以把它轉換成一個Observable,並且像上面一樣做(儘管任務更容易處理單個值)。 –

相關問題