Although this may not be a frequently used feature, downloading and saving files from inside our app can be a cool addition, especially if our app is using social media or anything else where users may want to share files or pictures.
Normally, Windows 8 contains a Background Transfer API which provides us a class called BackgroundDownloader that is very useful if we need to download large files, and it comes with neat features such as tracking download progress, setting a cost policy and pausing support. However, this class is designed for more long term download operations and for small files it is more preferable to use http APIs. Using HttpWebRequest gives us a low level control over the download operation, which may be needed sometimes.
In this article, we will make an app that will download the file from a given link, save it to a place that user chooses, and open it with the default application associated with its extension.
Alright, we begin with creating a brand new blank Windows Store App project in Visual Studio.
Next, we will create our interface in MainPage.xaml, which will consist of a textbox (to get the file link), two buttons (one to initiate download and second to open the file after it is downloaded), a progress bar to indicate the download is in progress and several related textblocks. It will look like this:
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}"> <ProgressBar x:Name="ProgressBar" VerticalAlignment="Top" Visibility="Collapsed"/> <TextBox x:Name="TextBoxLink" HorizontalAlignment="Left" Margin="100,123,0,0" VerticalAlignment="Top" Width="500"/> <TextBlock HorizontalAlignment="Left" Margin="100,100,0,0" TextWrapping="Wrap" Text="File link:" VerticalAlignment="Top" FontSize="15"/> <Button x:Name="ButtonDownload" Content="Download" HorizontalAlignment="Left" Margin="100,160,0,0" VerticalAlignment="Top"/> <TextBlock x:Name="TextBlockDownloadComplete" HorizontalAlignment="Left" Margin="100,203,0,0" TextWrapping="Wrap" Text="Download complete." VerticalAlignment="Top" FontSize="15" Visibility="Collapsed"/> <Button x:Name="ButtonOpenFile" Content="Open File" HorizontalAlignment="Left" Margin="100,226,0,0" VerticalAlignment="Top" Visibility="Collapsed"/> </Grid>
Then, we get right into the action by filling the Click events of both buttons in MainPage.xaml.cs:
using Windows.UI.Popups; using Windows.Storage.Pickers; using Windows.Storage; using System.Net;
StorageFile downloadedFile; public MainPage() { this.InitializeComponent(); } async private void ButtonDownload_Click(object sender, RoutedEventArgs e) { if (!String.IsNullOrEmpty(TextBoxLink.Text)) { string fileName = null; string fileExtension = null; try { fileName = TextBoxLink.Text.Substring(TextBoxLink.Text.LastIndexOf('\\'), (TextBoxLink.Text.LastIndexOf('.') - TextBoxLink.Text.LastIndexOf('\\'))); fileExtension = TextBoxLink.Text.Substring(TextBoxLink.Text.LastIndexOf('.'), (TextBoxLink.Text.Length - 1) - TextBoxLink.Text.LastIndexOf('.')); } catch { MessageDialog messageDialog = new MessageDialog("Could not determine the name and the extension of the file."); messageDialog.ShowAsync(); } if (fileName != null && fileExtension != null) { FolderPicker folderPicker = new FolderPicker(); folderPicker.SuggestedStartLocation = PickerLocationId.Downloads; folderPicker.ViewMode = PickerViewMode.Thumbnail; folderPicker.FileTypeFilter.Add("*"); StorageFolder folder = await folderPicker.PickSingleFolderAsync(); if (folder != null) { try { ButtonDownload.IsEnabled = false; ProgressBar.IsIndeterminate = true; ProgressBar.Visibility = Visibility.Visible; Uri address = new Uri(TextBoxLink.Text, UriKind.Absolute); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(address); WebResponse response = await request.GetResponseAsync(); Stream stream = response.GetResponseStream(); StorageFile file = await folder.CreateFileAsync(fileName, CreationCollisionOption.GenerateUniqueName); await Windows.Storage.FileIO.WriteBytesAsync(file, ReadStream(stream)); downloadedFile = file; ButtonDownload.IsEnabled = true; ProgressBar.Visibility = Visibility.Collapsed; ProgressBar.IsIndeterminate = false; TextBlockDownloadComplete.Visibility = Visibility.Visible; ButtonOpenFile.Visibility = Visibility.Visible; } catch { MessageDialog messageDialog = new MessageDialog("Your computer has gained self-awareness. You have 10 seconds to shut it down before it achieves world dominance."); // ^_^ messageDialog.ShowAsync(); ButtonDownload.IsEnabled = true; ProgressBar.Visibility = Visibility.Collapsed; ProgressBar.IsIndeterminate = false; TextBlockDownloadComplete.Visibility = Visibility.Collapsed; ButtonOpenFile.Visibility = Visibility.Collapsed; downloadedFile = null; } } } } } public static byte[] ReadStream(Stream input) { byte[] buffer = new byte[16 * 1024]; using (MemoryStream ms = new MemoryStream()) { int read; while ((read = input.Read(buffer, 0, buffer.Length)) > 0) { ms.Write(buffer, 0, read); } return ms.ToArray(); } } async private void ButtonOpenFile_Click(object sender, RoutedEventArgs e) { if (downloadedFile != null) { await Windows.System.Launcher.LaunchFileAsync(downloadedFile); } }
Ok, let’s just inspect step by step what we have written.
In the download button, we first try to determine the name and extension of the file, which will be needed when we are saving it. Then, we prompt the user to select which folder we should download the file to. This is a necessary step, because due to security reasons we can not just directly reach any file or folder, so we need to ask this to our user. Next, we asynchronously download the file provided in the link via HttpWebRequest as a Stream, convert that stream to a byte array, and finally write the contents of the byte array to a file in the selected folder (and therefore, save it). Lastly, in the open file button, we open the file with the default program associated with its extension.
Aand, that’s just it. 🙂 Let’s run our application and try to download something (I tried to download the banner of my blog):
As a parting note, keep in mind that this is useful for small files only, but I’ve been able to download files that were around 3-4 megabytes. Larger than that, and you’re better off with BackgroundDownloader class.
Here‘s the link to the source code of our app.
Thank you for reading. 🙂