2017-02-07 19 views
1

RestSharpを使用してサードパーティに接続するASP.NET MVCアプリケーションを使用して、ドメイン名のリストを受け取った後、結果の各ドメインの詳細を受け取ることができます。部分的なRESTレスポンスを受け取ったまま受け取ります

私は応答が部分的なパケットで起こっていると考えています。RestSharpは、すべてのパケットが受信されてデータを非直列化形式で出力するまで待機しています。

問題のペイロードは次のようになります。 「ヘッダー」が最初に表示され、直ちにビューに戻るようにする応答です。

[ 
{"header":{"names":["test.1","test.2","test.3","test.4","test.5","test.6"]}} 
, 
{"name":"test.1","can":"transfer?"} 
, 
{"name":"test.2","can":"transfer?"} 
, 
{"name":"test.3","can":"transfer?"} 
, 
{"name":"test.4","can":"transfer?"} 
, 
{"name":"test.5","can":"transfer?"} 
, 
{"name":"test.6","can":"register"} 
] 

実行のための2つの実装、同期1つずつ非同期現在ありません:

public T ExecuteGetRequest<T>(RestRequest request) where T : class 
{ 
    try 
    { 
     IRestResponse response = _client.Execute(request); 

     if (response.ErrorException == null) 
     { 
      return JsonConvert.DeserializeObject<T>(response.Content); 
     } 
     return null; 
    } 
    catch (Exception ex) 
    { 
     return null; 
    } 
} 

public Task<T> ExecuteGetRequestAsync<T>(RestRequest request) where T : new() 
{ 
    try 
    { 
     var source = new TaskCompletionSource<T>(); 
     _client.ExecuteAsync<T>(request, (response) => { source.SetResult(response.Data); }); 
     return source.Task; 
    } 
    catch (Exception ex) 
    { 
     return null; 
    } 
} 

実装するアプリケーションのためのローカルAPIコールがありますが、残りのデータは、より少ない時間に敏感ですこのようになります検索使用して非同期:レスポンスをinpterpretsし、クライアントに関連する検索結果を得られ

public async Task<DomainSearchResults> DomainSearchAsync(string domain) 
{ 
    var request = _client.CreateRequest("domain-search/{domain}", Method.GET); 
    request.AddUrlSegment("domain", domain); 
    var response = await _client.ExecuteGetRequestAsync<List<DomainSearch>>(request); 
    return new DomainSearchResults(response); 
} 

これは、すべてのデータがサードパーティによって送信されたときに、オブジェクトがビューに戻ってそれに応じて配置されるという意味で問題なく動作します。ただし、要求の完全な完了には最大20秒かかる場合がありますが、これはユーザーにとっては特に役に立ちません。

完全な応答を受け取る前に、不完全な応答を呼び出しビューに返すようにExecuteGetRequestAsyncを適合させる方法はありますか?

私の最初の試みは、このようにたくさん見える:

public Task<T> ExecuteGetRequestAsyncIncomplete<T>(RestRequest request) where T : new() 
{ 
    try 
    { 
     var source = new TaskCompletionSource<T>(); 
     _client.ExecuteAsync<T>(request, (response) => 
     { 
      source.SetResult(response.Data); 
      if (response.StatusCode == HttpStatusCode.PartialContent) 
      { 
       // Somehow return part of this response 
      } 

     }); 
     return source.Task; 
    } 
    catch (Exception ex) 
    { 
     return null; 
    } 
} 

@Evkの答えからに取り組んでUPDATE

が、ここでは具体的には、部分的な結果を返すために、新しいコールは次のようになります。このシナリオのために:私たちはSTRのどこにいる私たちが知っているように、要するに

public async Task<T> ExecuteGetRequestPartial<T>(RestRequest request) where T : new() 
{ 

    try 
    { 
     var source = new TaskCompletionSource<T>(); 
     request.ResponseWriter = (st) => { 
      using (var reader = new StreamReader(st)) 
      { 
       var sb = new StringBuilder(); 
       // read response 100 chars at a time 
       char[] buffer = new char[1]; 
       int read = 0; 
       while ((read = reader.Read(buffer, 0, buffer.Length)) > 0) 
       { 
        sb.Append(buffer, 0, read); 
        // now here you have your partial response 
        // you need to somehow parse it and feed to your view 
        // note that you should wait until you get some meaningful part, like first "header" element 
        // for example at some point there might be ["header":{"names":["te < partial response 
        if (sb.ToString().Contains("header") && sb.ToString().EndsWith("}")) 
        { 
         sb.Append("}]"); 
         source.SetResult(JsonConvert.DeserializeObject<T>(sb.ToString())); 
         return; 
        } 
       } 
       // at this point you have full response in sb 
      } 
     }; 
     await _client.ExecuteGetTaskAsync<T>(request); 
     return await source.Task; 
    } 
    catch (Exception ex) 
    { 
     return default(T); 
    } 
} 

、バッファは、1つの文字に短縮されましたing。次に、部分的な結果を有効なJSONに変換するために、オブジェクトの最後をチェックし、手動で余分な "}]"を結果に追加して返します。

ニースエブ!

答えて

1

最初に、httpステータス「部分コンテンツ」はあなたのケースとは関係ありません。これは、Rangeヘッダーを使用した要求に対する応答用です。

代わりに必要なのは、応答が配信されるのを待って、完全な応答が配信され、デシリアライズされるのを待つことなくです。通常のHttpWebRequestを使用する方が簡単ですが、RestSharpを使用する場合も可能です。 部分(したがって、無効)jsonを手動で逆シリアル化する必要があることに注意してください。ここにスケッチがあります:

public static Task<T> ExecuteGetRequestAsync<T>(RestRequest request) where T : new() { 
     var client = new RestClient("http://google.com"); 
     try { 
      var source = new TaskCompletionSource<T>(); 
      request.ResponseWriter = (st) => { 
       using (var reader = new StreamReader(st)) { 
        var sb = new StringBuilder(); 
        // read response 100 chars at a time 
        char[] buffer = new char[100]; 
        int read = 0; 
        while ((read = reader.Read(buffer, 0, buffer.Length)) > 0) { 
         sb.Append(buffer, 0, read); 
         // now here you have your partial response 
         // you need to somehow parse it and feed to your view 
         // note that you should wait until you get some meaningful part, like first "header" element 
         // for example at some point there might be ["header":{"names":["te < partial response 
        } 
        // at this point you have full response in sb 
       } 
      }; 
      client.ExecuteAsync<T>(request, null); 
      return source.Task; 
     } 
     catch (Exception ex) { 
      return null; 
     } 
    } 
関連する問題