2016-12-25 1 views
0

Я знаю, что этот вопрос был представлен несколько раз, но последние ответы датируются, и я задаюсь вопросом, будет ли доступно решение сегодня? Это не запрос функции. Я скорее ищу любое обходное решение, которое сработает.C# RestSharp Library - отчет Прогресс при загрузке большого «потока приложений/octect»

Я использую RestSharp на клиенте, который говорит с моим API. API отвечает с помощью «application/octect-stream», который может занять до нескольких минут. Ссылка на GitHub code here.

public void Download() 
{ 
    if (NewerApp == null) return; 

     var client = new RestClient(ServerAddress); 
     var request = new RestRequest("/Apps/", Method.POST); 
     request.AddParameter("id", CurrentApp.EncryptedId()); 
     request.AddParameter("action", "download"); 

     var asyncHandle = client.ExecuteAsync<App>(request, response => { 
      HandleResponseToDownloadRequest(response); 
     }); 
} 

Мне нужно сообщить о ходе приема «ответа» на мой пользовательский интерфейс, чтобы создать индикатор выполнения или что-то в этом роде. Я уже знаю ожидаемый объем данных, которые будут получены (через предыдущий ответ API), мне просто нужно было бы знать, сколько байтов было получено до получения и анализа полного ответа.

Я не верю, что RestSharp в настоящее время предлагает тип отчета о прогрессе, не так ли? Я вижу несколько подходов:

  1. Использование client.DownloadData (request) .SaveAs (путь);. Возможно, файл создается во время его загрузки. Я мог бы прочитать размер файла, чтобы сообщить о ходе загрузки. Но мое первое впечатление заключается в том, что клиент сначала загружает данные, а затем сохраняет файл. В этом случае это не помогло бы.
  2. Использование потока для загрузки ответа. Регулярно оценивайте размер потока или каждый раз, когда размер буфера расширяется.
  3. Измените тип ответа от API на другой (отправьте данные в JSON, например?).
  4. Любой другой вариант?

Что вы думаете? Кто-нибудь смог сообщить о ходе загрузки?

Могу ли я получить доступ к RawBytes из «ответа», пока ExecuteAsync все еще выполняется? Должен ли я использовать Execute (без Asyn) вместо этого? Должен ли я использовать поток и обновление смотреть размер потока при регулярных обновлениях?

ответ

0

Мне удалось получить отчет о ходе работы, но не использовать RestSharp. Я использовал System.Net.HttpClient на основании ответа kievichere. Поскольку kievic выделено, ключевым здесь является то, что aClient.SendAsync возвращается после получения и чтения заголовков HTTP, но контент по-прежнему загружается. Затем содержимое медленно загружается через поток в цикле while. RestSharp, похоже, не позволяет этого, или я не мог этого достичь.

public async Task DownloadAsync(Action<bool> callback) 
    { 
     if (NewerApp == null) return; 

     // Your original code. 
     HttpClientHandler aHandler = new HttpClientHandler(); 
     aHandler.ClientCertificateOptions = ClientCertificateOption.Automatic; 
     HttpClient aClient = new HttpClient(aHandler); 
     aClient.DefaultRequestHeaders.ExpectContinue = false; 
     HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Post, ServerAddress + "/Apps/"); 
     string content = "id=" + CurrentApp.EncryptedId() + "&action=download"; 
     message.Content = new StringContent(content); 
     HttpResponseMessage response = await aClient.SendAsync(message, 
      HttpCompletionOption.ResponseHeadersRead); // Important! ResponseHeadersRead. 

     // New code. 
     Stream stream = await response.Content.ReadAsStreamAsync(); 
     MemoryStream memStream = new MemoryStream(); 

     // Start reading the stream 
     var res = stream.CopyToAsync(memStream); 

     // While reading the stream 
     while (true) 
     { 
      // Report progress 
      this.DownloadedSize = memStream.Length; 
      this.Progress = 100.0 * (double)memStream.Length/(double)NewerApp.Filesize; 

      // Leave if no new data was read 
      if (res.IsCompleted) 
      { 
       // Report progress one last time 
       this.DownloadedSize = memStream.Length; 
       this.Progress = 100.0 * (double)memStream.Length/(double)NewerApp.Filesize; 

       break; 
      } 
     } 

     // Get the bytes from the memory stream 
     byte[] responseContent = new byte[memStream.Length]; 
     memStream.Position = 0; 
     memStream.Read(responseContent, 0, responseContent.Length); 

     // Function has ended - return whether the app was donwloaded 
     // properly and verified, or not 
     callback(HandleResponseToDownloadRequest(responseContent)); 
    } 

Каждый раз, когда this.DownloadedSize и this.Progress присваивается новое значение, палят событие, которое может быть перехвачено в пользовательском интерфейсе.

 private double progress = 0; 
    /// <summary> 
    /// Progress of the download of the App. From 0.0 (%) to 100.0 (%) 
    /// </summary> 
    public double Progress 
    { 
     get { return progress; } 
     set 
     { 
      // Max/Min 
      double val = value; 
      if (val > 100.0) val = 100; 
      else if (val < 0.0) val = 0.0; 

      // Assign value 
      if (progress != val) 
      { 
       progress = val; 
       OnProgressReport("Progress"); 
       OnPropertyChanged("Progress"); 
      } 
     } 
    } 

    public long downloadedSize = 0; 
    /// <summary> 
    /// Quantity of bytes downloaded of the app. 
    /// Note: there can be more bytes downloaded than advertized because 
    /// the quantity of advertize filesize is not encrypted while the 
    /// received bytes are encrypted. 
    /// TODO: advertize the size of the encrypted file. 
    /// </summary> 
    public long DownloadedSize 
    { 
     get 
     { 
      return downloadedSize; 
     } 
     set 
     { 
      if (downloadedSize != value) 
      { 
       downloadedSize = value; 
       OnDownloadedSizeReport("DownloadedSize"); 
      } 
     } 
    } 

/// <summary> 
    /// Fired when the progress of the download of the app file 
    /// has updated (more bytes received). 
    /// </summary> 
    public event PropertyChangedEventHandler ProgressReport; 
    protected void OnProgressReport(string name) 
    { 
     PropertyChangedEventHandler handler = ProgressReport; 
     if (handler != null) 
     { 
      handler(this, new PropertyChangedEventArgs(name)); 
     } 
    } 

    /// <summary> 
    /// Fired when the progress of the download of the app file 
    /// has updated (more bytes received). 
    /// </summary> 
    public event PropertyChangedEventHandler DownloadedSizeReport; 
    protected void OnDownloadedSizeReport(string name) 
    { 
     PropertyChangedEventHandler handler = DownloadedSizeReport; 
     if (handler != null) 
     { 
      handler(this, new PropertyChangedEventArgs(name)); 
     } 
    } 

Я называю DownloadAsync так:

// Start the download - await makes the execution of the method in background 
// so that UI can refresh and keep responsive. 
// downloaded: bool, true if file properly downloaded 
// Updater_AppDownloaded: function called once download has ended (failed or succeeded, either way) 
await System.Threading.Tasks.Task.Run(() => 
    Updater.DownloadAsync(downloaded =>  
     Updater_AppDownloaded(downloaded))); 
Смежные вопросы