bezzad / Downloader

Fast, cross-platform and reliable multipart downloader with asynchronous progress events for .NET applications.
MIT License
1.25k stars 193 forks source link

Callback error occurred when using version 3.0.4 #139

Closed 2366621450 closed 1 year ago

2366621450 commented 1 year ago

i need help

Callback error occurred when using version 3.0.4

my config: Visual Studio 2022 WPF Project Target .NET Framework4.8

**Callback name: DownloadProgressChanged, parameter two:Downloader.DownloadProgressChangedEventArgs

“.TotalBytesToReceive“ callback Always the same as ”ReceivedBytesSize” and “.ProgressPercentage“ always callback 100**

look the out:

Total:1.00KB - Downloaded:1.00KB - 0.86B / s - 100.000% - NeedTime: ... Total:25.79MB - Downloaded:25.79MB - 1.90MB / s - 100.000% - NeedTime: ... Total:42.54MB - Downloaded:42.54MB - 1.96MB / s - 100.000% - NeedTime: ... Total:65.74MB - Downloaded:65.74MB - 2.05MB / s - 100.000% - NeedTime: end

this is my code:


    public partial class MainWindow : Window
    {
        private List<DownloadService> dss = new List<DownloadService>();
        public MainWindow()
        {
            InitializeComponent();

            Complex();
        }

        public async Task Complex()
        {

            //Create Config
            DownloadConfiguration downloadConfiguration = new DownloadConfiguration()
            {
                ChunkCount = 8,
                MaxTryAgainOnFailover = 6,
                ParallelDownload = true,
                RangeDownload = false
            };

            //Create Downloader
            DownloadService downloader = new DownloadService(downloadConfiguration);

            this.dss.Add(downloader);

            // DownloadStarted event
            downloader.DownloadStarted += (object sender, DownloadStartedEventArgs e) => { };

            // ChunkDownloadProgressChanged enent
            downloader.ChunkDownloadProgressChanged += (object sender, Downloader.DownloadProgressChangedEventArgs e) => { };

            // DownloadProgressChanged event
            downloader.DownloadProgressChanged += (object sender, Downloader.DownloadProgressChangedEventArgs e) =>
            {
                Console.WriteLine("Total:" + getSizeString(e.TotalBytesToReceive)
                    + " - Downloaded:" + getSizeString(e.ReceivedBytesSize)
                    + " - " + getSizeString((long)e.BytesPerSecondSpeed)
                    + " / s - " + $"{e.ProgressPercentage:F3}".Replace("/", ".")
                    + "% - NeedTime:");
            };

            // Completed event
            downloader.DownloadFileCompleted += (object sender, AsyncCompletedEventArgs e) =>
            {
                if (!e.Cancelled && e.Error == null)
                {
                    Console.WriteLine("Task Download Success" + e.UserState);
                }
                else
                {
                    Console.WriteLine("Task Download Fail:" + e.UserState);
                }
            };

            //set download param
            string filePath = @"C:\Users\Allen\Desktop\download\6.mp4";
            string url = @"http://mirror.aarnet.edu.au/pub/TED-talks/911Mothers_2010W-480p.mp4";
            await downloader.DownloadFileTaskAsync(url, filePath);

        }
    }
bezzad commented 1 year ago

This issue is due to the server of the URL not supporting the Content-Length field in the response header. Specifically, when this field is missing or set to zero, the Download function will continue to download data until it receives zero bytes which it mean is the end of the file.

When the Download function does not receive information about the size of the file it is downloading, it cannot accurately determine how much of the file has been downloaded. As a result, the function assumes that the downloaded size is equal to the total size of the file, leading to a ProgressPercentage of 100%. However, since the function cannot determine the actual end of the file, it continues to download data until it receives zero bytes, as this indicates that it has reached the end of the content.

2366621450 commented 1 year ago

Content-Length

Can I manually set Content Length? If so, what should I do?

bezzad commented 1 year ago

Unfortunately, it is not possible to accurately determine the actual file size that will be downloaded if the server does not support the "Content-Length" field in the response header. However, you can try changing the download URL to a mirror link that supports this setting. Most servers support the "Content-Length" field, but in some cases, this issue may occur due to the server's invalid configuration.

2366621450 commented 1 year ago

Unfortunately, it is not possible to accurately determine the actual file size that will be downloaded if the server does not support the "Content-Length" field in the response header. However, you can try changing the download URL to a mirror link that supports this setting. Most servers support the "Content-Length" field, but in some cases, this issue may occur due to the server's invalid configuration.

Okay, but I think the file size should be obtained from the ContentLength attribute of the Response, so that even if some servers do not support Content Length fields, the callback will not encounter the above problem. Here is the method to obtain ContentLength from the Response. hope you can use or adopt a similar method to optimize the project:

public static long getRemoteFileSize(string url)
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            request.Method = "HEAD";
            long fileSize = -1;
            using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
            {
                if (response.StatusCode == HttpStatusCode.OK)
                {
                    fileSize = response.ContentLength;
                }
            }

            return fileSize;
        }
bezzad commented 1 year ago

Yes, I told you above that Content-Length should be obtained from the Response, but it has a 1 value sometimes like your URL. So, the Downloader can't reach the actual file size and start downloading without knowing when the download will be complete.

These are your response headers: image

bezzad commented 1 year ago

I remember the Downloader can also read Content-Range instead of Content-Length when it hasn't been provided from the headers. So, I imported your URL to the sample project. It downloaded correctly and without any issues!

If you have this issue again, please add your URL to the DownloadList.json file of the sample project. like below json:

[
  {
    "FileName": "D:\\TestDownload\\911Mothers_2010W-480p.mp4",
    "Url": "http://mirror.aarnet.edu.au/pub/TED-talks/911Mothers_2010W-480p.mp4"
  }
]

So, go to the Request class and add a breakpoint in the FetchResponseHeaders method to know what is your response headers when you call it. After that please send me the value of _responseHeaders to check it. Thanks.

image

2366621450 commented 1 year ago

我记得下载器也可以读取,Content-Range而不是Content-Length当它没有从标题中提供时。因此,我将您的 URL 导入了示例项目。它下载正确,没有任何问题题!

如果您再次遇到这个问题,请将您的URL添加到DownloadList.json显示项目的文件中。像下面的json:

[
  {
    "FileName": "D:\\TestDownload\\911Mothers_2010W-480p.mp4",
    "Url": "http://mirror.aarnet.edu.au/pub/TED-talks/911Mothers_2010W-480p.mp4"
  }
]

因此,转到Request类并在方法中添加一个断点FetchResponseHeaders,以方便在调用它时知道您的响应标头是什么。之后,请将值发给我_responseHeaders以进行检。谢谢。

图片

Okay, thank you