Exemple #1
0
        //// Here we receive the response from the server. We do not check for the "Accept-Ranges"
        //// response header, in order to find out if the server supports resuming, because it MAY
        //// send the "Accept-Ranges" response header, but is not required to do so. This is
        //// unreliable, so we'll just continue and catch the exception that will occur if not
        //// supported and send it the DownloadCompleted event. We also don't check if the
        //// Content-Length is '-1', because some servers return '-1', eventhough the file/webpage
        //// you're trying to download is valid. e.ProgressPercentage returns '-1' in that case.
        private void GetResponse_Callback(IAsyncResult result)
        {
            HttpWebRequestState State             = (HttpWebRequestState)result.AsyncState;
            FileStream          DestinationStream = null;
            HttpWebResponse     Response          = null;
            Stopwatch           Duration          = new Stopwatch();

            byte[] Buffer                   = new byte[8192];
            int    BytesRead                = 0;
            int    ElapsedSeconds           = 0;
            int    DownloadSpeed            = 0;
            int    DownloadProgress         = 0;
            int    BytesReceivedThisSession = 0;

            try
            {
                //'// Get response
                Response = (HttpWebResponse)(State.Request.EndGetResponse(result));

                //// Asign Response headers to ReadOnly ResponseHeaders property.
                _ResponseHeaders = Response.Headers;

                //// If the server does not reply with an 'OK (200)' message when starting
                //// the download or a 'PartialContent (206)' message when resuming.
                if ((int)Response.StatusCode != System.Convert.ToInt32(HttpStatusCode.OK) & (int)Response.StatusCode != System.Convert.ToInt32(HttpStatusCode.PartialContent))
                {
                    //// Send error message to anyone who is listening.
                    OnDownloadCompleted(new FileDownloadCompletedEventArgs(new Exception(Response.StatusCode.ToString()), false, State.userToken));
                    return;
                }

                //// Create/open the file to write to.
                if (State.ResumeDownload)
                {
                    //// If resumed, then create or open the file.
                    DestinationStream = new FileStream(State.LocalFilePath, FileMode.OpenOrCreate, FileAccess.Write);
                }
                else
                {
                    //// If not resumed, then create the file, which will delete the existing file if it already exists.
                    DestinationStream = new FileStream(State.LocalFilePath, FileMode.Create, FileAccess.Write);
                    //// Get the ContentLength only when we're starting the download. Not when resuming.
                    _ContentLenght = Response.ContentLength;
                }

                //// Moves stream position to beginning of the file when starting the download.
                //// Moves stream position to end of the file when resuming the download.
                DestinationStream.Seek(0, SeekOrigin.End);

                //// Start timer to get download duration / download speed, etc.
                Duration.Start();

                //// Get the Response Stream.
                using (Stream responseStream = Response.GetResponseStream())
                {
                    do
                    {
                        //// Read some bytes.
                        BytesRead = responseStream.Read(Buffer, 0, Buffer.Length);
                        if (BytesRead > 0)
                        {
                            //// Write incoming data to the file.
                            DestinationStream.Write(Buffer, 0, BytesRead);
                            //// Count the total number of bytes downloaded.
                            _TotalBytesReceived += BytesRead;
                            //// Count the number of bytes downloaded this session (Resume).
                            BytesReceivedThisSession += BytesRead;
                            //// Get number of elapsed seconds (need round number to prevent 'division by zero' error).
                            ElapsedSeconds = System.Convert.ToInt32(Duration.Elapsed.TotalSeconds);

                            //// Update frequency: No Delay, every Half a Second or every Second.
                            if (ProgressUpdateFrequency == UpdateFrequency.NoDelay)
                            {
                                //// Calculate download speed in bytes per second.
                                if (ElapsedSeconds > 0)
                                {
                                    DownloadSpeed = BytesReceivedThisSession / ElapsedSeconds;
                                }
                                //// Send download progress to anyone who is listening.
                                OnDownloadProgressChanged(new FileDownloadProgressChangedEventArgs(_TotalBytesReceived, (int)_ContentLenght, ElapsedSeconds, DownloadSpeed, State.userToken));
                            }
                            else if (ProgressUpdateFrequency == UpdateFrequency.HalfSecond)
                            {
                                if (System.Convert.ToInt32(Duration.ElapsedMilliseconds - DownloadProgress) >= 500)
                                {
                                    DownloadProgress = (int)Duration.ElapsedMilliseconds;
                                    //// Calculate download speed in bytes per second.
                                    if (ElapsedSeconds > 0)
                                    {
                                        DownloadSpeed = BytesReceivedThisSession / ElapsedSeconds;
                                    }
                                    //// Send download progress to anyone who is listening.
                                    OnDownloadProgressChanged(new FileDownloadProgressChangedEventArgs(_TotalBytesReceived, (int)_ContentLenght, ElapsedSeconds, DownloadSpeed, State.userToken));
                                }
                            }
                            else if (ProgressUpdateFrequency == UpdateFrequency.Second)
                            {
                                if (System.Convert.ToInt32(Duration.ElapsedMilliseconds - DownloadProgress) >= 1000)
                                {
                                    DownloadProgress = (int)Duration.ElapsedMilliseconds;
                                    //// Calculate download speed in bytes per second.
                                    if (ElapsedSeconds > 0)
                                    {
                                        DownloadSpeed = BytesReceivedThisSession / ElapsedSeconds;
                                    }
                                    //// Send download progress to anyone who is listening.
                                    OnDownloadProgressChanged(new FileDownloadProgressChangedEventArgs(_TotalBytesReceived, (int)_ContentLenght, ElapsedSeconds, DownloadSpeed, State.userToken));
                                }
                            }

                            //// Exit loop when paused.
                            if (_CancelAsync)
                            {
                                break;
                            }
                        }
                    } while (!(BytesRead == 0));
                }


                //// Send download progress once more. If the UpdateFrequency has been set to
                //// HalfSecond or Second, then the last percentage returned might be 98% or 99%.
                //// This makes sure it's 100%.
                OnDownloadProgressChanged(new FileDownloadProgressChangedEventArgs(_TotalBytesReceived, (int)_ContentLenght, System.Convert.ToInt32(Duration.Elapsed.TotalSeconds), DownloadSpeed, State.userToken));

                if (_CancelAsync)
                {
                    //// Send completed message (Paused) to anyone who is listening.
                    OnDownloadCompleted(new FileDownloadCompletedEventArgs(null, true, State.userToken));
                }
                else
                {
                    //// Send completed message (Finished) to anyone who is listening.
                    OnDownloadCompleted(new FileDownloadCompletedEventArgs(null, false, State.userToken));
                }
            }
            catch (Exception ex)
            {
                //// Send completed message (Error) to anyone who is listening.
                OnDownloadCompleted(new FileDownloadCompletedEventArgs(ex, false, State.userToken));
            }
            finally
            {
                //// Close the file.
                if (DestinationStream != null)
                {
                    DestinationStream.Flush();
                    DestinationStream.Close();
                    DestinationStream = null;
                }
                //// Stop and reset the duration timer.
                Duration.Reset();
                Duration = null;
                //// Signal we're not downloading anymore.
                _isbusy = false;
            }
        }
        protected override void BeforeBlockWrite([NotNull] Block block, [NotNull] PipelineInfo pipelineInfo)
        {
            var offset = (long)block.Position * pipelineInfo.BlockSize;

            DestinationStream.Seek(offset, SeekOrigin.Begin);
        }