private void TryCleanupExistingDownloadWebClient()
 {
     if (downloadWebClient == null)
     {
         return;
     }
     try
     {
         lock (this)
         {
             if (downloadWebClient != null)
             {
                 downloadWebClient.DownloadFileCompleted   -= OnDownloadCompleted;
                 downloadWebClient.DownloadProgressChanged -= OnDownloadProgressChanged;
                 downloadWebClient.OpenReadCompleted       -= OnOpenReadCompleted;
                 downloadWebClient.CancelAsync();
                 downloadWebClient.Dispose();
                 downloadWebClient = null;
             }
         }
     }
     catch (Exception e)
     {
         logger.Warn("Error while cleaning up web client : {0}", e.Message);
     }
 }
        private void TriggerWebClientDownloadFileAsync()
        {
            logger.Debug("Falling back to legacy DownloadFileAsync.");
            try
            {
                isFallback = true;
                string destinationDirectory = Path.GetDirectoryName(localFileName);
                if (destinationDirectory != null && !Directory.Exists(destinationDirectory))
                {
                    Directory.CreateDirectory(destinationDirectory);
                }
                TryCleanupExistingDownloadWebClient();

                downloadWebClient = CreateWebClient();
                downloadWebClient.DownloadFileAsync(fileSource, localFileName);
                logger.Debug("Download async started. Source: {0} Destination: {1}", fileSource, localFileName);
            }
            catch (Exception ex)
            {
                logger.Warn("Failed to download Source:{0}, Destination:{1}, Error:{2}.", fileSource, localFileName, ex.Message);
                if (!AttemptDownload())
                {
                    InvokeDownloadCompleted(CompletedState.Failed, localFileName, ex);
                }
            }
        }
        private DownloadWebClient CreateWebClient()
        {
            DownloadWebClient webClient = new DownloadWebClient();

            webClient.DownloadFileCompleted   += OnDownloadCompleted;
            webClient.DownloadProgressChanged += OnDownloadProgressChanged;
            webClient.OpenReadCompleted       += OnOpenReadCompleted;
            return(webClient);
        }
        private void Download(Uri source, string fileDestination, long totalBytesToReceive)
        {
            try
            {
                long seekPosition;
                FileHelpers.TryGetFileSize(fileDestination, out seekPosition);

                TryCleanupExistingDownloadWebClient();
                downloadWebClient = CreateWebClient();
                downloadWebClient.OpenReadAsync(source, seekPosition);
                logger.Debug("Download started. Source: {0} Destination: {1} Size: {2}", source, fileDestination, totalBytesToReceive);
            }
            catch (Exception e)
            {
                logger.Debug("Download failed: {0}", e.Message);
                if (!AttemptDownload())
                {
                    InvokeDownloadCompleted(CompletedState.Failed, localFileName, e);
                }
            }
        }
        private void OnOpenReadCompleted(object sender, OpenReadCompletedEventArgs args)
        {
            DownloadWebClient webClient = sender as DownloadWebClient;

            if (webClient == null)
            {
                logger.Warn("Wrong sender in OnOpenReadCompleted: Actual:{0} Expected:{1}", sender.GetType(), typeof(DownloadWebClient));
                return;
            }

            lock (cancelSync)
            {
                if (isCancelled)
                {
                    logger.Debug("Download was cancelled.");
                    return;
                }

                if (!webClient.HasResponse)
                {
                    logger.Debug("DownloadWebClient returned no response.");
                    TriggerWebClientDownloadFileAsync();
                    return;
                }

                bool   appendExistingChunk = webClient.IsPartialResponse;
                Stream destinationStream   = CreateDestinationStream(appendExistingChunk);
                if (destinationStream != null)
                {
                    TrySetStreamReadTimeout(args.Result, (int)SourceStreamReadTimeout.TotalMilliseconds);

                    worker                  = new StreamCopyWorker();
                    worker.Completed       += OnWorkerCompleted;
                    worker.ProgressChanged += OnWorkerProgressChanged;
                    worker.CopyAsync(args.Result, destinationStream, TotalBytesToReceive);
                }
            }
        }
        /// <summary>
        /// OnDownloadCompleted event handler
        /// </summary>
        /// <param name="sender">Sender object</param>
        /// <param name="args">AsyncCompletedEventArgs instance</param>
        protected void OnDownloadCompleted(object sender, AsyncCompletedEventArgs args)
        {
            DownloadWebClient webClient = sender as DownloadWebClient;

            if (webClient == null)
            {
                logger.Warn("Wrong sender in OnDownloadCompleted: Actual:{0} Expected:{1}", sender.GetType(), typeof(DownloadWebClient));
                InvokeDownloadCompleted(CompletedState.Failed, localFileName);
                return;
            }

            if (args.Cancelled)
            {
                logger.Debug("Download cancelled. Source: {0} Destination: {1}", fileSource, localFileName);
                if (!isPaused)
                {
                    DeleteDownloadedFile();
                }
                InvokeDownloadCompleted(CompletedState.Canceled, localFileName);
                readyToDownload.Set();
            }
            else if (args.Error != null)
            {
                if (isFallback)
                {
                    DeleteDownloadedFile();
                }

                ////We may have NameResolutionFailure on internet connectivity problem.
                ////We don't use DnsFallbackResolver if we successfully started downloading, and then got internet problem.
                ////If we change [this.fileSource] here - we lose downloaded chunk in Cache (i.e. we create a new Cache item for new [this.fileSource]
                if (attemptNumber == 1 && DnsFallbackResolver != null && IsNameResolutionFailure(args.Error))
                {
                    Uri newFileSource = DnsFallbackResolver.Resolve(fileSource);
                    if (newFileSource != null)
                    {
                        fileSource = newFileSource;
                        logger.Debug("Download failed in case of DNS resolve error. Retry downloading with new source: {0}.", fileSource);
                        AttemptDownload();
                        return;
                    }
                }

                logger.Debug("Download failed. Source: {0} Destination: {1} Error: {2}", fileSource, localFileName, args.Error);

                if (!AttemptDownload())
                {
                    InvokeDownloadCompleted(CompletedState.Failed, null, args.Error);
                    readyToDownload.Set();
                }
            }
            else
            {
                if (useFileNameFromServer)
                {
                    localFileName = ApplyNewFileName(localFileName, webClient.GetOriginalFileNameFromDownload());
                }

                logger.Debug("Download completed. Source: {0} Destination: {1}", fileSource, localFileName);
                if (UseCaching)
                {
                    downloadCache.Add(fileSource, localFileName, webClient.ResponseHeaders);
                }

                ////we may have the destination file not immediately closed after downloading
                WaitFileClosed(localFileName, TimeSpan.FromSeconds(3));

                InvokeDownloadCompleted(CompletedState.Succeeded, localFileName, null);
                readyToDownload.Set();
            }
        }