Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avalonia: How do properly handle file downloads? #379

Open
dhhunter opened this issue Jan 30, 2025 · 5 comments
Open

Avalonia: How do properly handle file downloads? #379

dhhunter opened this issue Jan 30, 2025 · 5 comments

Comments

@dhhunter
Copy link

Greetings, as the question states how do you properly handle file downloads?

Thanks and God Bless,
- Dean

@dhhunter
Copy link
Author

dhhunter commented Jan 30, 2025

It seems that adding an event handler to any of the Download events (DownloadCancelled, DownloadCompleted, DownloadProgressChanged) throws a NullReferenceException in InternalDownloadHandler.OnDownloadUpdated, the problem appears to be with the CefDownloadItem! The CefDownloadItem is being Disposed() before OnDownloadUpdated can use it. To my pleasant surprise downloads work perfectly fine as fire and forget operations (not using DownloadCancelled, DownloadCompleted, DownloadProgressChanged); however, for my use case I really need to be able to track the download so I did a little debugging.

I believe that a simple change to WebView.InternalDownloadHandler like below will solve the problem:

protected override void OnDownloadUpdated(CefBrowser browser, CefDownloadItem downloadItem, CefDownloadItemCallback callback) 
{
    var fullPath = downloadItem.FullPath;
    var receivedBytes = downloadItem.ReceivedBytes;
    var totalBytes = downloadItem.TotalBytes;

    if (downloadItem.IsComplete) {
        if (OwnerWebView.DownloadCompleted != null) {
            OwnerWebView.AsyncExecuteInUI(() => OwnerWebView.DownloadCompleted?.Invoke(fullPath));
        }
    } else if (downloadItem.IsCanceled) {
        if (OwnerWebView.DownloadCancelled != null) {
            OwnerWebView.AsyncExecuteInUI(() => OwnerWebView.DownloadCancelled?.Invoke(fullPath));
        }
    } else {
        if (OwnerWebView.DownloadProgressChanged != null) {
            OwnerWebView.AsyncExecuteInUI(() => OwnerWebView.DownloadProgressChanged?.Invoke(fullPath, receivedBytes, totalBytes));
        }
    }
}

Thanks and God Bless,
- Dean

@joaompneves
Copy link
Collaborator

Can you submit a PR?

@dhhunter
Copy link
Author

dhhunter commented Feb 3, 2025

I have never submitted a PR before; however, I doubt it is that difficult! I am generally kind of hesitant to work on other peoples code; however, it would probably be a good exercise for me. I will work on that today!

Thanks!

@dhhunter
Copy link
Author

dhhunter commented Feb 3, 2025

It occurred to me that the way the API is designed tracking multiple downloads is potentially a little wonky since the downloadItem.Id is not sent as a parameter to the public download events. I do not want to break the public API so I will leave that decision for the project owners!

For now, I suppose a suitable work around would probably be to delay tracking (on the UI side anyway) the download until the resourcePath != "", especially in more advanced scenarios. Anyway, my further testing is delaying my PR!

@joaompneves
Copy link
Collaborator

joaompneves commented Feb 4, 2025

You can add events similiar to the existing ones, but with extra id param, so that we don't have breaking changes. I would probably create a class/record to put that data so that in the future this problem doesn't happen

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants