2015-01-21 13 views
6

Bu soru, Threading issues when using HttpClient for asynchronous file downloads numaralı telefonun bir takipçisi.Senkronize olmayan dosya karşıdan yüklemeleri için HttpClient kullanıldığında kontrol hatası

HttpClient kullanarak eşzamansız bir şekilde tamamlamak için bir dosya aktarımı almak için, SendEsync isteğine HttpCompletionOption.ResponseHeadersRead öğesini eklemeniz gerekir. Böylece, bu çağrı tamamlandığında, EnsureSuccessStatusCode'a bir çağrı ekleyerek isteğin ve yanıt başlıklarının hepsinin iyi olduğunu belirleyebileceksiniz. Bununla birlikte, veriler şu anda hala aktarılmaktadır.

Başlıklar gönderildikten sonra, ancak veri aktarımı tamamlanmadan önce meydana gelen hataları nasıl algılayabilirsiniz? Söz konusu hatalar kendilerini nasıl gösterir?

Bazı örnek kod yorum ile) hattı 109 işaretlenmiş soru noktası ile, aşağıdaki gibidir:

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Net.Http; 
using System.Threading.Tasks; 

namespace TestHttpClient2 
{ 
    class Program 
    { 
    /* Use Yahoo portal to access quotes for stocks - perform asynchronous operations. */ 

    static string baseUrl = "http://real-chart.finance.yahoo.com/"; 
    static string requestUrlFormat = "/table.csv?s={0}&d=0&e=1&f=2016&g=d&a=0&b=1&c=1901&ignore=.csv"; 

    static void Main(string[] args) 
    { 
     var activeTaskList = new List<Task>(); 

     string outputDirectory = "StockQuotes"; 
     if (!Directory.Exists(outputDirectory)) 
     { 
     Directory.CreateDirectory(outputDirectory); 
     } 

     while (true) 
     { 
     Console.WriteLine("Enter symbol or [ENTER] to exit:"); 
     string symbol = Console.ReadLine(); 
     if (string.IsNullOrEmpty(symbol)) 
     { 
      break; 
     } 

     Task downloadTask = DownloadDataForStockAsync(outputDirectory, symbol); 
     if (TaskIsActive(downloadTask)) 
     { 
      // This is an asynchronous world - lock the list before updating it! 
      lock (activeTaskList) 
      { 
      activeTaskList.Add(downloadTask); 
      } 

     } 
     else 
     { 
      Console.WriteLine("task completed already?!??!?"); 
     } 
     CleanupTasks(activeTaskList); 
     } 

     Console.WriteLine("Cleaning up"); 
     while (CleanupTasks(activeTaskList)) 
     { 
     Task.Delay(1).Wait(); 
     } 
    } 

    private static bool CleanupTasks(List<Task> activeTaskList) 
    { 
     // reverse loop to allow list item deletions 
     // This is an asynchronous world - lock the list before updating it! 
     lock (activeTaskList) 
     { 
     for (int i = activeTaskList.Count - 1; i >= 0; i--) 
     { 
      if (!TaskIsActive(activeTaskList[i])) 
      { 
      activeTaskList.RemoveAt(i); 
      } 
     } 
     return activeTaskList.Count > 0; 
     } 
    } 

    private static bool TaskIsActive(Task task) 
    { 
     return task != null 
      && task.Status != TaskStatus.Canceled 
      && task.Status != TaskStatus.Faulted 
      && task.Status != TaskStatus.RanToCompletion; 
    } 

    static async Task DownloadDataForStockAsync(string outputDirectory, string symbol) 
    { 
     try 
     { 
     using (var client = new HttpClient()) 
     { 
      client.BaseAddress = new Uri(baseUrl); 
      client.Timeout = TimeSpan.FromMinutes(5); 
      string requestUrl = string.Format(requestUrlFormat, symbol); 

      var request = new HttpRequestMessage(HttpMethod.Post, requestUrl); 
      var response = await client.SendAsync(request, 
      HttpCompletionOption.ResponseHeadersRead); 
      response.EnsureSuccessStatusCode(); 

      using (var httpStream = await response.Content.ReadAsStreamAsync()) 
      { 
      var timestampedName = FormatTimestampedString(symbol, true); 
      var filePath = Path.Combine(outputDirectory, timestampedName + ".csv"); 
      using (var fileStream = File.Create(filePath)) 
      { 
       await httpStream.CopyToAsync(fileStream); 
      } 
      } 
      // *****WANT TO DO MORE ERROR CHECKING HERE***** 
     } 
     } 
     catch (HttpRequestException ex) 
     { 
     Console.WriteLine("Exception on thread: {0}: {1}\r\n", 
      System.Threading.Thread.CurrentThread.ManagedThreadId, 
      ex.Message, 
      ex.StackTrace); 
     } 
     catch (Exception ex) 
     { 
     Console.WriteLine("Exception on thread: {0}: {1}\r\n", 
      System.Threading.Thread.CurrentThread.ManagedThreadId, 
      ex.Message, 
      ex.StackTrace); 
     } 
    } 

    static volatile string lastTimestampedString = string.Empty; 
    static volatile string dummy = string.Empty; 

    static string FormatTimestampedString(string message, bool uniquify = false) 
    { 
     // This is an asynchronous world - lock the shared resource before using it! 
     lock (dummy) 
     //lock (lastTimestampedString) 
     { 
     Console.WriteLine("IN - Thread: {0:D2} lastTimestampedString: {1}", 
      System.Threading.Thread.CurrentThread.ManagedThreadId, 
      lastTimestampedString); 

     string newTimestampedString; 

     while (true) 
     { 
      DateTime lastDateTime = DateTime.Now; 

      newTimestampedString = string.Format(
       "{1:D4}_{2:D2}_{3:D2}_{4:D2}_{5:D2}_{6:D2}_{7:D3}_{0}", 
       message, 
       lastDateTime.Year, lastDateTime.Month, lastDateTime.Day, 
       lastDateTime.Hour, lastDateTime.Minute, lastDateTime.Second, 
       lastDateTime.Millisecond 
       ); 
      if (!uniquify) 
      { 
      break; 
      } 
      if (newTimestampedString != lastTimestampedString) 
      { 
      break; 
      } 

      //Task.Delay(1).Wait(); 
     }; 

     lastTimestampedString = newTimestampedString; 
     Console.WriteLine("OUT - Thread: {0:D2} lastTimestampedString: {1}", 
      System.Threading.Thread.CurrentThread.ManagedThreadId, 
      lastTimestampedString); 

     return lastTimestampedString; 
     } 
    } 
    } 
} 
+2

'109 numaralı satırda işaretlenen soru ile):' satır numaralarını göstermiyorsanız/göstermiyorsanız, bireylerin satırları manuel olarak saymasını bekliyorsunuz .. lol – MethodMan

+0

Satır göstermenin bir yolu var mı? Kodu bozmadan numaralar? Eğer öyleyse, düzenlemeyi yapacağım.Öyle olduğu gibi, ekranımda yaklaşık 30 satırlık çizgiler alıyorum ve kaydırma çubuğunda 3 kez tıklarsam, açılır: // ***** BURADA HATALI KONTROL ETMEK İSTİYORUM **** * –

cevap

5

ben "// ***** ** BURADA KONTROLÜ DAHA HATA YAPMAK İSTİYORUM" ilgili kodu kopyalayıp biraz temizledik.

var request = new HttpRequestMessage(HttpMethod.Post, requestUrl); 
var response = await client.SendAsync(request, 
    HttpCompletionOption.ResponseHeadersRead); 
response.EnsureSuccessStatusCode(); 
using (var httpStream = await response.Content.ReadAsStreamAsync()) 
{ 
    var timestampedName = FormatTimestampedString(symbol, true); 
    var filePath = Path.Combine(outputDirectory, timestampedName + ".csv"); 
    using (var fileStream = File.Create(filePath)) 
    { 
     await httpStream.CopyToAsync(fileStream); 
    } 
} 

soru şey akışı okuma ve dosyaya kopyalayarak sırasında ters giderse, nedir?

Tüm mantıksal hataları zaten HTTP isteği ve tepki döngüsünün bir parçası olarak ele alınmıştır: Sunucu isteğinizi aldı, bu başarı (yanıtının başlık kısmı) ile yanıt verdi, geçerli karar verdi ve oldu Şimdi size sonucu gönderiyor (yanıtın vücut kısmı).

try 
{ 
    using (var httpStream = await response.Content.ReadAsStreamAsync()) 
    { 
     var timestampedName = FormatTimestampedString(symbol, true); 
     var filePath = Path.Combine(outputDirectory, timestampedName + ".csv"); 
     using (var fileStream = File.Create(filePath)) 
     { 
      await httpStream.CopyToAsync(fileStream); 
     } 
    } 
} 
catch (HttpRequestException e) 
{ 
    ... 
} 

:

şimdi sunucu çökmesini gibi şeylerdir meydana gelebilmektedir sadece hatalar

, bağlantı Benim anlayış bu böyle bir kod yazabilirsiniz anlamına HttpRequestException olarak tezahür edecektir vb kaybolması The documenation doesn't say much, unfortunately. The reference source doesn't either. En iyi seçeneğiniz bununla başlamak ve belki de yanıt gövdesinin yüklenmesi sırasında atılabilecek başka bir istisna türü olması durumunda HttpRequestException olmayan tüm istisnaları günlüğe kaydetmektir. aslında okumak asenkron tampon ile kendinizi bırakın

3

okumak başlık ve içerik okuma arasındadır kısmına daraltmak isterseniz,:

var httpStream = await response.Content.ReadAsStreamAsync(); 

Bakarsanız içeride ne oluyor yöntem, şunu görürsünüz:

public Task<Stream> ReadAsStreamAsync() 
{ 
    this.CheckDisposed(); 
    TaskCompletionSource<Stream> tcs = new TaskCompletionSource<Stream>(); 
    if (this.contentReadStream == null && this.IsBuffered) 
    { 
     this.contentReadStream = new MemoryStream(this.bufferedContent.GetBuffer(), 
                0, (int)this.bufferedContent.Length, 
                false, false); 
    } 
    if (this.contentReadStream != null) 
    { 
     tcs.TrySetResult(this.contentReadStream); 
     return tcs.Task; 
    } 
    this.CreateContentReadStreamAsync().ContinueWithStandard(delegate(Task<Stream> task) 
    { 
     if (!HttpUtilities.HandleFaultsAndCancelation<Stream>(task, tcs)) 
     { 
      this.contentReadStream = task.Result; 
      tcs.TrySetResult(this.contentReadStream); 
     } 
    }); 
    return tcs.Task; 
} 

CreateContentReadStreamAsync tüm okuma yapıyor biridir, içten, o LoadIntoBufferAsync arayacak hangi find here can.

Temel olarak, bu IOException ve ObjectDisposedException, kapsüller ya da (i son derece nadir olacağını düşünüyorum rağmen) bir ArgumentOutOfRangeException tampon 2 GB'tan büyük olduğunu görebiliriz.

+0

Açıkçası, iyi şeyler dağıtıldığı gün hastalandım ;-) Bu kaynağı nasıl gördün? –

+1

@anyoneis LOL. [http://www.symbolsource.com] veya ILSpy –

+0

görüntülerine bakabilirsiniz. Bu bilgiyi kullanarak bir kaynak görebilirsiniz: http://referencesource.microsoft.com/setup.html –