Learn how to handle the downloads in Cefsharp.

How to allow and manipulate downloads in Cefsharp

By default in your embed chromium-browser in WinForms using the Cefsharp library, if you try to navigate to a web page that allows you to download a file of any kind, you will notice that even when you click on the download button, nothing happens. There's no interaction with the browser about where to save the file nor is stored anywhere, no download progress, absolutely nothing.

In this article, I will explain to you how to easily allow downloads on your own Cefsharp instance in WinForms in 2 different ways.

1. Create a custom download handler class

You need to create a custom download handler class. This class will be assigned to the DownloadHandler property of the ChromiumWebBrowser instance. According to your needs and the allowed behavior, you may simply launch a save as dialog that will allow the user to customize the filename of the download wherever the user wants. The other option is to automatically store the files in the Downloads directory of the system.

1.A. Allow downloads launching the save as dialog

The first option will allow the user to select the path where the file will be downloaded using the system's dialog. Create the MyCustomDownloadHandler.cs file that will contain the following code:

using CefSharp;
using System;

namespace CefsharpSandbox
{
    class MyCustomDownloadHandler : IDownloadHandler
    {
        public event EventHandler<DownloadItem> OnBeforeDownloadFired;

        public event EventHandler<DownloadItem> OnDownloadUpdatedFired;

        public void OnBeforeDownload(IWebBrowser chromiumWebBrowser, IBrowser browser, DownloadItem downloadItem, IBeforeDownloadCallback callback)
        {
            if (downloadItem.IsValid)
            {
                Console.WriteLine("== File information ========================");
                Console.WriteLine(" File URL: {0}", downloadItem.Url);
                Console.WriteLine(" Suggested FileName: {0}", downloadItem.SuggestedFileName);
                Console.WriteLine(" MimeType: {0}", downloadItem.MimeType);
                Console.WriteLine(" Content Disposition: {0}", downloadItem.ContentDisposition);
                Console.WriteLine(" Total Size: {0}", downloadItem.TotalBytes);
                Console.WriteLine("============================================");
            }

            OnBeforeDownloadFired?.Invoke(this, downloadItem);

            if (!callback.IsDisposed)
            {
                using (callback)
                {
                    callback.Continue(
                        downloadItem.SuggestedFileName,
                        showDialog: true
                    );
                }
            }
        }

        /// https://cefsharp.github.io/api/51.0.0/html/T_CefSharp_DownloadItem.htm
        public void OnDownloadUpdated(IWebBrowser chromiumWebBrowser, IBrowser browser, DownloadItem downloadItem, IDownloadItemCallback callback)
        {
            OnDownloadUpdatedFired?.Invoke(this, downloadItem);

            if (downloadItem.IsValid)
            {
                // Show progress of the download
                if (downloadItem.IsInProgress && (downloadItem.PercentComplete != 0))
                {
                    Console.WriteLine(
                        "Current Download Speed: {0} bytes ({1}%)",
                        downloadItem.CurrentSpeed,
                        downloadItem.PercentComplete
                    );
                }

                if (downloadItem.IsComplete)
                {
                    Console.WriteLine("The download has been finished !");
                }
            }
        }
    }
}

1.B. Allow downloads and store them automatically in the downloads directory

The second option will automatically store the downloads that the browser processes inside a custom directory (usually the Downloads directory of the system). Create the MyCustomDownloadHandler.cs file that will contain the following code:

using CefSharp;
using System;
using System.IO;

namespace CefsharpSandbox
{
    class MyCustomDownloadHandler : IDownloadHandler
    {
        public event EventHandler<DownloadItem> OnBeforeDownloadFired;

        public event EventHandler<DownloadItem> OnDownloadUpdatedFired;

        public void OnBeforeDownload(IWebBrowser chromiumWebBrowser, IBrowser browser, DownloadItem downloadItem, IBeforeDownloadCallback callback)
        {
            if (downloadItem.IsValid)
            {
                Console.WriteLine("== File information ========================");
                Console.WriteLine(" File URL: {0}", downloadItem.Url);
                Console.WriteLine(" Suggested FileName: {0}", downloadItem.SuggestedFileName);
                Console.WriteLine(" MimeType: {0}", downloadItem.MimeType);
                Console.WriteLine(" Content Disposition: {0}", downloadItem.ContentDisposition);
                Console.WriteLine(" Total Size: {0}", downloadItem.TotalBytes);
                Console.WriteLine("============================================");
            }

            OnBeforeDownloadFired?.Invoke(this, downloadItem);

            if (!callback.IsDisposed)
            {
                using (callback)
                {
                    // Define the Downloads Directory Path
                    // You can use a different one, in this example we will hard-code it
                    string DownloadsDirectoryPath = "C:\\Users\\sdkca\\Downloads\\";
                    
                    callback.Continue(
                        Path.Combine(
                            DownloadsDirectoryPath, 
                            downloadItem.SuggestedFileName
                        ),
                        showDialog: false
                    );
                }
            }
        }

        /// https://cefsharp.github.io/api/51.0.0/html/T_CefSharp_DownloadItem.htm
        public void OnDownloadUpdated(IWebBrowser chromiumWebBrowser, IBrowser browser, DownloadItem downloadItem, IDownloadItemCallback callback)
        {
            OnDownloadUpdatedFired?.Invoke(this, downloadItem);

            if (downloadItem.IsValid)
            {
                // Show progress of the download
                if (downloadItem.IsInProgress && (downloadItem.PercentComplete != 0))
                {
                    Console.WriteLine(
                        "Current Download Speed: {0} bytes ({1}%)",
                        downloadItem.CurrentSpeed,
                        downloadItem.PercentComplete
                    );
                }

                if (downloadItem.IsComplete)
                {
                    Console.WriteLine("The download has been finished !");
                }
            }
        }
    }
}

As mentioned in the code, we hard-code the Downloads directory path. If you want to dynamically obtain the downloads directory of your system, you may want to use a custom method that you can find in this other article.

2. Use custom downloads handler class as the default one

Now you need to simply assign a new instance of the recently created class to the DownloadHandler property of your ChromiumWebBrowser instance on your initialization code like this:

CefSettings settings = new CefSettings();
// Some settings if you have, here
// Initialize cef with the provided settings
Cef.Initialize(settings);

// Create a browser component
ChromiumWebBrowser chromeBrowser = new ChromiumWebBrowser("https://ourcodeworld.com");
// Register your Custom Downloads Handler
chromeBrowser.DownloadHandler = new MyCustomDownloadHandler();

// ...
// Rest of your code
// ...

And that's all that you need to do to handle downloads through Cefsharp in your project. Now if you launch your application and start some download, you will find the following information in your console output:

== File information ========================
 File URL: https://somedomain.com/myimage.png
 Suggested FileName: myimage.png
 MimeType: image/png
 Content Disposition: attachment; filename="myimage.png"
 Total Size: 28635
============================================
(Appears only when downloading the file)
Current Download Speed: 28635 bytes (100%)
Current Download Speed: 28635 bytes (100%)
Current Download Speed: 0 bytes (100%)
Current Download Speed: 0 bytes (100%)
The download has been finished !

Happy coding ❤️!


Senior Software Engineer at Software Medico. Interested in programming since he was 14 years old, Carlos is a self-taught programmer and founder and author of most of the articles at Our Code World.

Sponsors