How to download a file to KnownFolder using BackroundTransfer? - c#

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?

Related

Blazor UI hanging during memory file upload

I'm working on a simple blazor application that receives a file upload and stores it. I am using BlazorInputFile and I can't work out why copying the stream to MemoryStream is causing the browser to freeze.
The details of how to use (and how it's implemented) BlazorInputFile are explained in this blog post: Uploading Files in Blazor.
var ms = new MemoryStream();
await file.Data.CopyToAsync(ms); // With a 1MB file, this line took 3 seconds, and froze the browser
status = $"Finished loading {file.Size} bytes from {file.Name}";
Sample project/repo: https://github.com/paulallington/BlazorInputFileIssue
(this is just the default Blazor app, with BlazorInputFile implemented as per the article)
Use await Task.Delay(1); as mentioned on Zhi Lv's comment in this post blazor-webassembly upload file can't show progress?
var buffer = new byte[imageFile.Size];
await Task.Delay(1);
await imageFile.OpenReadStream(Int64.MaxValue).ReadAsync(buffer);
pratica.Files.Add(new FilePraticaRequest()
{
Contenuto = buffer,
Nome = imageFile.Name,
});
StateHasChanged();
I've experienced the same issue. I've tried both predefined components such as Steve Sanderssons file upload and MatBlazor fileupload and also my own component to handle fileuploads. Small files are not a problem. Once the files are a bit larger in size the UI will hang itself. MemoryOutOfBoundsException (or similar). So no, async/await can't help you release the UI.
I have put so much effort into this issue, one solution, that I am currently using, is to do all fileuploads with javascript instead of blazor. Just use javascript to get the file and post it up to the server. No JSInterop..
However, it seems like it is a memory issue in webassembly mono.
Read more here: https://github.com/dotnet/aspnetcore/issues/15777
Note: I haven't tried this on the latest Blazor version. So I'm not sure it's fixed or not.
You wait for the copy result, so the app freeze, you can refactor your code like this;
var ms = new MemoryStream();
file.Data.CopyToAsync(ms).ContinueWith(async task =>
{
if (task.Exception != null)
{
throw task.Exception; // Update this by your convenience
}
status = $"Finished loading {file.Size} bytes from {file.Name}";
await InvokeAsync(StateHasChanged).ConfigureAwait(false); // informs the component the status changed
}; // With a 1MB file, this line took 3 seconds, and should not froze the browser

Problem with extracting audio from a video file (android)

I need to convert an mp4 (or any other video format) to mp3 or wav file. I am using C# Xamarin.Forms. Any library I used either doesn't work for me, or isn't compatible with android. I have tried using Xamarin.Android.FFMpeg and Xobe.FFMpeg.
I repost this because it was marked as duplicate and I clearly stated that that solution isn't working for me. This is the post that was flagged as duplicate: How can I extract the audio out of a video file? (android) . Please, I tried it but it just gives me the "Downloading Video Converter" dialog with a progress bar when I try to run the code in the solution, Also, it doesn't even extract the audio so after the user waits such a long time, it turned out as a waste of time.
Thanks in advance! :)
EDIT 1:
This is the code I am using:
private async Task<string> ExtractAudioAsync(string path, Action<string> logger = null,
Action<int, int> onProgress = null)
{
List<string> cmd = new List<string>();
cmd.Add("-i");
cmd.Add(path + ".mp4");
cmd.Add("-vn");
cmd.Add("-acodec");
cmd.Add("copy");
cmd.Add(path + ".mp3");
string cmdParams = string.Join(' ', cmd);
await FFMpeg.Xamarin.FFMpegLibrary.Run(Context, cmdParams);
return path + ".mp3";
}
There are no exceptions thrown. When the Run method is called it just shows on the application the following dialog:
After that, it just closes the dialog and goes to the return line without even extracting the audio out of the video. Even if I run this code again it does the same thing, downloading it again.
EDIT 2:
I tried adding the -report option but it just did the same thing and did not save any log file. Am I doing something wrong?

UWP StorageFile.CopyAsync() Throwing Error: "Value does not fall within the expected range."

I am trying to overwrite a file with a new version inside of an AppData sub-directory.
Current process is that the user has to select the File to overwrite, and the folder directory it sits in separately so that I can add them to the future access list. Later on the user can select from a collection of images, and it's at that point that it needs to copy and overwrite the destination file. The code I've tried to do this is as follows:
// lets try to copy file to wallpaper default location.
ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
var faToken = localSettings.Values["WallpaperStorageFileFAToken"] as string;
var faTokenFolder = localSettings.Values["WallpaperStorageFolderFAToken"] as string;
var destinationFile = await LoadExistingFileSelection(faToken);
var destinationFolder = await LoadExistingFolderSelection(faTokenFolder);
StorageFile movedFile = null;
try
{
movedFile = await imageFile.CopyAsync(destinationFolder, destinationFile.Name, NameCollisionOption.ReplaceExisting);
}
catch (Exception genEx)
{
//
}
The Fa tokens are taken after an FileOpenPicker is used by the User to get the StorageFile and a FolderPicker used to get the StorageFolder for the directory of the destination.
LoadExistingFolderSelection and LoadExistingFileSelection use the following bits of code to get the StorageFiles and StorageFolder
await StorageApplicationPermissions.FutureAccessList.GetFileAsync(faToken);
and
await StorageApplicationPermissions.FutureAccessList.GetFolderAsync(faFolderToken);
The issue is that this line:
imageFile.CopyAsync(destinationFolder, destinationFile.Name, NameCollisionOption.ReplaceExisting);
Throws this error:
"Value does not fall within the expected range."
and that's it, literally nothing else, any thoughts would be great.
Backslashes... Honestly this is one of those moments in you're development career where you just sit there and sigh, because it's just so dumb.
So I could happily retrieve the image I wanted to copy absolutely fine into a StorageFile object, with a path that contained 1 additional backslash that the Windows OS File Explorer wouldn't have batted an eye lid about.
No problem so far, great proceed to then run a copy operation against that, and suddenly you get the
“Value does not fall within the expected range.”
exception, argue-ably one of the least helpful exceptions relating to a problem with a file path that I've seen.
So there you have it, backslashes, really carefully examine the Path property. Hindsight. Normally I would just remove that question because this answer isn't particularly any kind of great revelation. But I figure it can stay as a warning about the fearsome backslash and UWP's Storage API.

Windows 10 UWP App XElement.Save() "Access is denied" exception

I'm writing a Windows 10 UWP App, and I'm hitting a snag. I have a Settings.xml in the root of the app folder that I will use to store the DB connection information, as well as a few ancillary settings. I can load the XML fine, and my function to edit works (I can extract the XML through debug and see the changes). My problem comes when trying to write the edited file. I understand that I don't have direct access to the file system with UWP, however I've tried several different methods I've found online to work within my constraints and still can't find one that works. I always come back with an "Access is denied" error in some form or another. Here is a snippet of what my Save function looks like right now. Any help would be greatly appreciated.
try
{
XElement xmlSettings = XElement.Load(uri: "Settings.xml");
XElement xmlNode;
//Do Stuff (clipped for brevity).
StorageFolder folder = ApplicationData.Current.LocalFolder;
StorageFile file = await folder.CreateFileAsync(desiredName: "Settings.xml", options: CreationCollisionOption.ReplaceExisting);
Stream stream = await file.OpenStreamForWriteAsync();
xmlSettings.Save(stream);
Error = "";
}
catch (Exception e)
{
Error = "SaveSettings";
}
I added an xml file to my solution (in the root) and copy pasted your code.
It runs the first time, but gets the exception the second time. The reason is that your stream is not closed. You should use it with using:
using (Stream stream = await file.OpenStreamForWriteAsync())
{
xmlSettings.Save(stream);
}
With this change the code worked even the second time.

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.

Categories