private Task <string?> DownloadWithProgress(SourceRepository sourceRepository, PackageIdentity packageIdentity) { var progressDialogText = Resources.Dialog_DownloadingPackage; if (packageIdentity.HasVersion) { progressDialogText = string.Format(CultureInfo.CurrentCulture, progressDialogText, packageIdentity.Id, packageIdentity.Version); } else { progressDialogText = string.Format(CultureInfo.CurrentCulture, progressDialogText, packageIdentity.Id, string.Empty); } string?description = null; int? percent = null; var updated = 0; var progressDialogLock = new object(); #pragma warning disable CA2000 // Dispose objects before losing scope (handled in finally below) var progressDialog = new ProgressDialog { Text = progressDialogText, WindowTitle = Resources.Dialog_Title, ShowTimeRemaining = true, CancellationText = "Canceling download..." }; // polling for Cancel button being clicked var cts = new CancellationTokenSource(); var timer = new System.Timers.Timer(100); #pragma warning restore CA2000 // Dispose objects before losing scope timer.Elapsed += (o, e) => { lock (progressDialogLock) { if (progressDialog.CancellationPending) { timer.Stop(); cts.Cancel(); } else if (Interlocked.CompareExchange(ref updated, 0, 1) == 1) { progressDialog.ReportProgress(percent.GetValueOrDefault(), null, description); } } }; var tcs = new TaskCompletionSource <string?>(); progressDialog.DoWork += (object?sender, DoWorkEventArgs args) => { var t = DoWorkAsync(); t.Wait(cts.Token); tcs.TrySetResult(t.Result); }; progressDialog.RunWorkerCompleted += (object?sender, RunWorkerCompletedEventArgs args) => { MainWindow.Value.Activate(); }; progressDialog.ShowDialog(MainWindow.Value); timer.Start(); async Task <string?> DoWorkAsync() { try { var httpProgressProvider = new ProgressHttpHandlerResourceV3Provider(OnProgress); var repository = PackageRepositoryFactory.CreateRepository(sourceRepository.PackageSource, new[] { new Lazy <INuGetResourceProvider>(() => httpProgressProvider) }); var downloadResource = await repository.GetResourceAsync <DownloadResource>(cts !.Token).ConfigureAwait(false); using var sourceCacheContext = new SourceCacheContext() { NoCache = true }; var context = new PackageDownloadContext(sourceCacheContext, Path.GetTempPath(), true); using var result = await downloadResource.GetDownloadResourceResultAsync(packageIdentity, context, string.Empty, NullLogger.Instance, cts.Token).ConfigureAwait(false); if (result.Status == DownloadResourceResultStatus.Cancelled) { throw new OperationCanceledException(); } if (result.Status == DownloadResourceResultStatus.NotFound) { throw new Exception($"Package '{packageIdentity.Id} {packageIdentity.Version}' not found"); } var tempFilePath = Path.GetTempFileName(); using (var fileStream = File.OpenWrite(tempFilePath)) { await result.PackageStream.CopyToAsync(fileStream).ConfigureAwait(false); } return(tempFilePath); } catch (OperationCanceledException) { return(null); } catch (Exception exception) { OnError(exception); return(null); } finally { timer !.Stop(); timer.Dispose(); cts !.Dispose(); // close progress dialog when done lock (progressDialogLock !) { progressDialog !.Dispose(); } } } void OnProgress(long bytesReceived, long?totalBytes) { if (totalBytes.HasValue) { // TODO: remove ! once https://github.com/dotnet/roslyn/issues/33330 is fixed percent = (int)((bytesReceived * 100L) / totalBytes) !; description = string.Format( CultureInfo.CurrentCulture, "Downloaded {0} of {1}...", FileSizeConverter.Convert(bytesReceived, typeof(string), null, CultureInfo.CurrentCulture), FileSizeConverter.Convert(totalBytes.Value, typeof(string), null, CultureInfo.CurrentCulture)); } else { percent = null; description = string.Format( CultureInfo.CurrentCulture, "Downloaded {0}...", FileSizeConverter.Convert(bytesReceived, typeof(string), null, CultureInfo.CurrentCulture)); } Interlocked.Exchange(ref updated, 1); } return(tcs.Task); }
private async Task <string> DownloadWithProgress(SourceRepository sourceRepository, PackageIdentity packageIdentity) { var progressDialogText = Resources.Dialog_DownloadingPackage; if (packageIdentity.HasVersion) { progressDialogText = string.Format(CultureInfo.CurrentCulture, progressDialogText, packageIdentity.Id, packageIdentity.Version); } else { progressDialogText = string.Format(CultureInfo.CurrentCulture, progressDialogText, packageIdentity.Id, string.Empty); } string description = null; int? percent = null; var updated = false; var progressDialogLock = new object(); var progressDialog = new ProgressDialog { Text = progressDialogText, WindowTitle = Resources.Dialog_Title, ShowTimeRemaining = true, CancellationText = "Canceling download..." }; // polling for Cancel button being clicked var cts = new CancellationTokenSource(); var timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(200) }; timer.Tick += (o, e) => { lock (progressDialogLock) { if (progressDialog.CancellationPending) { timer.Stop(); cts.Cancel(); } else if (updated) { if (!progressDialog.IsOpen) { progressDialog.ProgressBarStyle = percent.HasValue ? ProgressBarStyle.ProgressBar : ProgressBarStyle.MarqueeProgressBar; progressDialog.ShowDialog(MainWindow.Value); } progressDialog.ReportProgress(percent.GetValueOrDefault(), null, description); updated = false; } } }; timer.Start(); try { var httpProgressProvider = new ProgressHttpHandlerResourceV3Provider(OnProgress); var additionalProviders = new[] { new Lazy <INuGetResourceProvider>(() => httpProgressProvider) }; var repository = PackageRepositoryFactory.CreateRepository(sourceRepository.PackageSource, additionalProviders); var downloadResource = await repository.GetResourceAsync <DownloadResource>(cts.Token); using (var sourceCacheContext = new SourceCacheContext() { NoCache = true }) { var context = new PackageDownloadContext(sourceCacheContext, Path.GetTempPath(), true); using (var result = await downloadResource.GetDownloadResourceResultAsync(packageIdentity, context, string.Empty, NullLogger.Instance, cts.Token)) { if (result.Status == DownloadResourceResultStatus.Cancelled) { throw new OperationCanceledException(); } if (result.Status == DownloadResourceResultStatus.NotFound) { throw new Exception(string.Format("Package '{0} {1}' not found", packageIdentity.Id, packageIdentity.Version)); } var tempFilePath = Path.GetTempFileName(); using (var fileStream = File.OpenWrite(tempFilePath)) { await result.PackageStream.CopyToAsync(fileStream); } return(tempFilePath); } } } catch (OperationCanceledException) { return(null); } catch (Exception exception) { OnError(exception); return(null); } finally { timer.Stop(); // close progress dialog when done lock (progressDialogLock) { progressDialog.Close(); progressDialog = null; } MainWindow.Value.Activate(); } void OnProgress(long bytesReceived, long?totalBytes) { if (totalBytes.HasValue) { percent = (int)((bytesReceived * 100L) / totalBytes); description = string.Format( CultureInfo.CurrentCulture, "Downloaded {0} of {1}...", FileSizeConverter.Convert(bytesReceived, typeof(string), null, CultureInfo.CurrentCulture), FileSizeConverter.Convert(totalBytes.Value, typeof(string), null, CultureInfo.CurrentCulture)); } else { percent = null; description = string.Format( CultureInfo.CurrentCulture, "Downloaded {0}...", FileSizeConverter.Convert(bytesReceived, typeof(string), null, CultureInfo.CurrentCulture)); } updated = true; } }