Puppeteer-sharp - wait for download complete after clicking link - c#

I try to click a download link that triggers a file download. The click and the download works and the file is downloaded to the downloads folder.
string xpath = "//a";
IElementHandle ret = await page.WaitForXPathAsync(xpath);
await Delay();
await ret.FocusAsync();
await Delay();
await ret.ClickAsync();
await Delay();
After clicking on the download link, I need to wait until the file has been completely downloaded which takes up to several seconds before I can do something with the file. Its not a good solution just to add a delay as I have no idea how long it takes for the file to download.
How do I wait for a file download to complete in puppeteer-sharp?
Is there something like this?
await page.WaitForResponseAsync()
or
await page.on('response', (response)=>{ console.log(response, response._url)}
I do not know how to write this in puppeteer-sharp

Related

How to know file download progress status in server-side Blazor?

Currently, I download byte arrays as files using JsInterop.
Here is my JS file:
function downloadFile(fileName, base64String) {
const url = "data:application/octet-stream;base64," + base64String;
const anchorElement = document.createElement('a');
anchorElement.href = url;
anchorElement.download = fileName ?? '';
anchorElement.click();
anchorElement.remove();
}
And here is a method in my razor component:
async Task DownloadFile(byte[] file)
{
ShowMessage("Start");
await JSRuntime.InvokeVoidAsync("downloadFile", "FileName", Convert.ToBase64String(file));
ShowMessage("End");
}
This code works, and I am able to download files. My issue is that I cannot implement the progress bar, or even show the loading spinner because await JSRuntime has no idea about an actual file download size and its progress. JSRuntime only launches the process of downloading and immediately continues to the next line of code.
In the code above ShowMessage("Start") and ShowMessage("End") are both shown one after another as soon as I click the download button, but the file in the browser downloads much later (depending on the file size).
How may I await the download process and execute relevant code only when the file has been downloaded? And it would be even better if I could read downloaded bytes to show a progress bar with percentages.
Update: for test purposes, I upload the file from the browser and store it in a byte[] variable. Then I download the same file from the variable using JS. Even though I store the file in the memory, it still takes time to download the file. I suppose that when I store a file in memory, it is already on my PC (client), and should download immediately. But instead, my window gets frozen for the duration of downloading the file. Tested on 6 - 11- 20 MB files. The bigger file, the more I have to wait for it to download.
I suggest you should be show message ShowMessage("Start") and ShowMessage("End"); in function downloadFile at JS

How to download a file to KnownFolder using BackroundTransfer?

I'm testing BackgroundTransfer on Windows Phone 8.1 RT and I'm facing strange issue, when I try to download a file to one of the KnownFolders.
The code is as follow:
string address = #"http://www.onereason.org/archive/wp-content/uploads/2012/02/universe.jpg";
StorageFile tempFile = await KnownFolders.PicturesLibrary.CreateFileAsync("temp.jpg", CreationCollisionOption.ReplaceExisting);
BackgroundDownloader manager = new BackgroundDownloader();
var operation = manager.CreateDownload(new Uri(address), tempFile);
IProgress<DownloadOperation> progressH = new Progress<DownloadOperation>((p) =>
{ Debug.WriteLine("Transferred: {0}, Total: {1}", p.Progress.BytesReceived, p.Progress.TotalBytesToReceive); });
await operation.StartAsync().AsTask(progressH);
Debug.WriteLine("BacgroundTransfer created");
It's quite simple and works if I download to ApplicationData.Current.LocalFolder, but if I do it like above, the transfer never completes, though the progresshandler says all bytes have been received:
The code never reaches the line Debug.WriteLine("BacgroundTransfer created"); and if I take a look at proccesses on the phone, I can see that RuntimeBroker is using the CPU at 100%:
obviously it's also continuing its work after you finish debugging the app and the phone becomes hotter and hotter. The fastest way to cancel this situation is to uninstall the app, as with this action all corresponding background transfers are cancelled.
All the necessary capabilieties are being set. I can for example download the file to LocalFolder and then copy to KnownFolder, but it's additional redundant action. Is there a way to download a file directly to KnownFolder? Have I missed something?

How can I open a file I've added to my Windows Store App project programatically?

I want to load a PDF file in response to a Tapped event.
I added the file to my project (Add > Existing Item), set "Build Action" to "Content" and "Copy to Output Directory" to "Copy if newer"
I'm thinking the code I need may be something like this:
async Task LoadTutorial()
{
await Launcher.LaunchUriAsync(new Uri("what should be here to access the output folder?"));
}
If I'm right, what do I need to pass as the Uri? Otherwise, how is this accomplished?
UPDATE
On a related note, to add an image to the XAML using the suggested scheme, I thought this would work:
<Image Source="ms-appx:///assets/axXAndSpaceLogo.jpg"></Image>
...but it doesn't.
UPDATE 2
Trying this to open the PDF file (which is located in the root of the project, not in a subfolder):
async private void OpenTutorial()
{
IStorageFolder folder = Windows.ApplicationModel.Package.Current.InstalledLocation;
IStorageFile file = await folder.GetFileAsync("ms-appx:///PlatypusTutorial.pdf");
await Launcher.LaunchFileAsync(file);
}
...resulted in this runtime exception, thrown on the first line above:
UPDATE 3
And with this, adapted from the link provided:
var uri = new System.Uri("ms-appx:///ClayShannonResume.pdf");
var file = Windows.Storage.StorageFile.GetFileFromApplicationUriAsync(uri);
await Launcher.LaunchFileAsync(file);
...I get the compile time errors:
The best overloaded method match for 'Windows.System.Launcher.LaunchFileAsync(Windows.Storage.IStorageFile)' has some invalid arguments
-and:
Argument 1: cannot convert from 'Windows.Foundation.IAsyncOperation' to 'Windows.Storage.IStorageFile'
...on the last line.
UPDATE 4
According to page 76 of "Pro Windows 8 Programming" by Lecrenski, Netherlands, Sanders, and Ashely, this should work:
<Image Source="Assets/axXAndSpaceLogo.jpg" Stretch="None"></Image>
...(IOW, the "ms-appx:///" jazz is unnecessary), and it more or less does. In my particular case, with my (large) image, I had to do this:
<Image Source="Assets/axXAndSpaceLogo.jpg" Width="120" Height="80" HorizontalAlignment="Left"></Image>
Without the width and height settings, the image displayed bigger than a rhinoceros, and hugging the right side of the flyout.
UPDATE 5
I find that this works to open a PDF file ("PlatypusTut.pdf" has been added to the project, with "Build Action" set to "Content" and "Copy to Output Diretory" set to "Copy if newer"):
IStorageFolder folder = Windows.ApplicationModel.Package.Current.InstalledLocation;
IStorageFile file = await folder.GetFileAsync("PlatypusTut.pdf");
bool success = await Launcher.LaunchFileAsync(file);
if (!success)
{
MessageDialog dlgDone = new MessageDialog("Unable to open the Tutorial at this time. Try again later.");
await dlgDone.ShowAsync();
}
...but I wonder if this will only work at design-time, locally. Will this work when installed on user's machines, too? IOW, is it enough to simply pass "PlatypusTut.pdf" to GetFileAsync()?
Use the ms-appx protocol (e.g. ms-appx:///assets/image.png )to reference items in the apps package. See How to load file resources (XAML)
UPDATE:
Use GetFileFromApplicationUriAsync with ms-appx to find the file in the app package. If the file is marked as content and included in the app package then it will be available once deployed and not just from in the debugger. ms-appx:///PlatypusTut.pdf will find the PlatypusTut.pdf in the root of the app package.
StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///PlatypusTut.pdf"));
await Launcher.LaunchFileAsync(file);
We did it that way:
public async Task OpenResearchAsync(string path)
{
if (path.ToLower().StartsWith("http://"))
{
await Launcher.LaunchUriAsync(new Uri(path));
}
else
{
IStorageFolder folder = Windows.ApplicationModel.Package.Current.InstalledLocation;
IStorageFile file = await folder.GetFileAsync(path);
await Launcher.LaunchFileAsync(file);
}
}

WinRT DownloadOperation doesn't return anything until either the download is complete or 1MB has downloaded

I'm using the WinRT BackgroundDownloader to create a DownloadOperation and then waiting for it to call back with progress and data downloaded so far. My problem is that the callback doesn't get invoked unless the download is complete or exactly 1MB of data has been downloaded. I want to get a progress report back earlier than that.
Has anyone else experienced this problem and does anyone have a solution? I feel like there's probably a setting somewhere to change the granularity of the download progress reports but I just can't find it anywhere.
Here's a code sample:
using System;
using System.Diagnostics;
using Windows.Networking.BackgroundTransfer;
using Windows.Storage;
...
var downloader = new BackgroundDownloader();
var storageFile = await KnownFolders.PicturesLibrary.CreateFileAsync("puppy.jpg", CreationCollisionOption.ReplaceExisting);
var downloadUri = new Uri("http://www.wallbest.com/wallpapers/2560x1600/puppy-eyes-beagle-www.wallbest.com.jpg");
var downloadOperation = downloader.CreateDownload(downloadUri, storageFile);
var progress = new Progress<DownloadOperation>(operation => Debug.WriteLine(operation.Progress.BytesReceived));
await downloadOperation.StartAsync().AsTask(progress);
Yes, that's the actual behavior: "WinRT DownloadOperation doesn't return anything until either the download is complete or 1MB has downloaded".
This class is intended for downloading large files in the background. For downloading objects smaller than 1MB you should just use asynchronous downloading using HttpClient.

How to identify whether a download is completed using an ashx handler

In one of our project we need the functionality to download a file from server to client location.
For this we are using an ashx handler to do the operation. Its working perfectly and we are able to download files.
Now we need a requirement like we need to update a field when a download is started and completed. Is there any way to do this.
Once we click the download link the Save as dialog box will appear and after that i think we don't have any control to check the progress. I think we even don't know which button is clicked ie we don't know whether the user is clicked a 'Yes' or 'No'.
Can anyone please suggest a method to know when the download is started and when it has been completed? We are using Asp.Net 2.0 with c#.
The handler used for download is given below
string fileUrl = string.Empty;
if (context.Request["fileUrl"] != null)
{
fileUrl = context.Request["fileUrl"].ToString();
}
string filename = System.IO.Path.GetFileName(fileUrl);
context.Response.ClearContent();
context.Response.ContentType = "application/exe";
context.Response.AddHeader("content-disposition", String.Format("attachment; filename={0}", filename));
context.Response.TransmitFile(fileUrl);
context.Response.Flush();
The file is downloaded from an aspx page method like
private void DownloadExe()
{
string downloadUrl = "Test.exe");
Response.Redirect("Test.ashx?fileUrl=" + downloadUrl, false);
}
Your ASHX handler knwos if download started (since it is actually get called) and when download is completed (end of handler is reached). You may even get some progress server side if you are writing response manually in chunks, this way you also may be able to detect some cases when user cancels download (if writing to response stream fails at some point).
Depending on your needs you may be able to transfer this information to other pages (i.e. via session state) or simply store in some database.
How about this:
Response.BufferOutput = false;
Response.TransmitFile(fileUrl);
//download complete code
If you disable response output buffering then it won't move past the line of code that sends the file to the client until the client has finished receiving it. If they cancel the download half way through it throws a HttpException so the download complete code doesn't get run.
You could also place your download complete code after your call to flush the buffer. But it's better not to enable buffering when sending large binary files to save on server memory.
Ok I had the same problem and jumped over this site:
Check over coockies
This works great for me.

Categories