I can't seem to read a file from a background task in a windows store app. Here's the code that reads the file content:
async private static Task<string> ReadAsync(string FileName)
{
var folder = ApplicationData.Current.LocalFolder;
var file = await folder.GetFileAsync(FileName);
Windows.Storage.Streams.IRandomAccessStreamWithContentType inputStream = null;
try
{
inputStream = await file.OpenReadAsync();
}
catch (Exception ex)
{
throw (ex);
}
string content = string.Empty;
using (Stream stream = inputStream.AsStreamForRead())
{
using (StreamReader reader = new StreamReader(stream))
{
try
{
// *** program exits on this line
content = await Task.Run(() => reader.ReadToEnd());
}
catch(Exception ex)
{
// no error is caught
content = ex.Message;
}
}
}
return content;
}
The program exits on the line that calls ReadToEnd() on the StreamReader - no error is caught in the try catch block. In the output window I get:
The program '[8968] backgroundTaskHost.exe: Managed (v4.0.30319)' has exited with code 1 (0x1)
Is it possible to access files a background task? If so, where am I going wrong?
It would be helpful if you posted your IBackgroundTask code. Without seeing it I suspect you didn't call GetDeferral() inside it, e.g.:
public async void Run(IBackgroundTaskInstance taskInstance)
{
var deferral = taskInstance.GetDeferral();
var contents = await ReadAsync("MyFile.txt");
deferral.Complete();
}
You need to call GetDeferral() whenever you are making asynchronous calls inside your background task. This way you tell the runtime it needs to wait for the asynchronous call to complete and not stop the background task as soon as Run exits.
Once you're done, i.e. usually at the end of your Run method, you need to call Complete() on the deferral instance to notify the runtime that you're done.
There are already system classes (DataReader) to read file asynchronously, so I'm not sure why you decided to write your own.
Related
I'm working on a script that downloads a ~100mb file from an AWS bucket, and want to wait for it to finish before continuing.
Using https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/dotnetv3/S3/scenarios/TransferUtilityBasics/TransferUtilityBasics/TransferMethods.cs
this script, I have the following code as my function:
public static async Task<string> DownloadAWSFile(string fileName, string filePath)
{
TransferUtility fileTransferUtility = new TransferUtility(s3Client);
var success = await TransferMethods.DownloadSingleFileAsync(fileTransferUtility, Config.AWS_BucketName, fileName, filePath);
if (success)
{
return "done";
}
else
{
return "error";
}
}
Which is called by this code:
Task<string> task = AWSGET.DownloadAWSFile("filetodownload.zip", "C:\\path\\to\\download\\");
task.Wait();
if (task.Result == "done")
{
MessageBox.Show("Done Downloading", "Configuration", MessageBoxButton.OK, MessageBoxImage.Warning);
}
else
{
MessageBox.Show("Error", "Configuration", MessageBoxButton.OK, MessageBoxImage.Warning);
}
the download code works fine on its own. I click the button that runs the AWSGET.DOwnloadAWSFile function, it works fine.
Once I had that working, I changed that function to a task, as shown above.
Now, it runs, it does the download, but it doesnt trigger anything - the alerts in this case - when its done, and it freezes up my program.
Any advice you can offer is appreciated. Still pretty new to this.
This is the problem:
task.Wait();
You should not use blocking waits on async code, because it can lead to deadlocks (which you are experiencing, check out Don't Block on Async Code by Stephen Cleary). The best approach is just to await the task:
var result = await AWSGET.DownloadAWSFile(...);
Also possibly you should consider using ConfigureAwait(false) inside the download method, JIC:
var success = await TransferMethods.DownloadSingleFileAsync(...).ConfigureAwait(false);
I've developed a queuing system in C#.NET and I'm trying to catch exceptions and retry errors from inside the tasks of the queue. I cannot use await to start-up the queue or run tasks as it will block execution. I need to catch and handle exceptions inside FileQueueTest.ProcessFile().
Below is the code I've written to demonstrate the queue. I've purposely put a non-existent file to force an exception. However, the exception is not handled in the try/catch block of the async task and crashing the program. I've included the program's output and a screenshot of the unhandled exception in Visual Studio.
Any help would be greatly appreciated! Thanks!
public class FileQueueTest : List<string>
{
SemaphoreSlim mutex = new SemaphoreSlim(1);
List<string> doneFiles = new List<string>();
public async Task Start()
{
// This call cannot block as files will be queued outside this class at any time.
Task.Factory.StartNew(WatchQueue);
}
async Task WatchQueue()
{
while (true)
{
await mutex.WaitAsync();
var nextFile = this.FirstOrDefault();
if (nextFile != null)
{
Task.Factory.StartNew(() => QueueAndWait(nextFile));
RemoveAt(0);
}
mutex.Release();
await Task.Delay(100);
}
}
async Task QueueAndWait(string filename)
{
await ProcessFile(filename);
await mutex.WaitAsync();
doneFiles.Add(filename);
mutex.Release();
}
public async Task QueueFile(string filename)
{
await mutex.WaitAsync();
Add(filename);
mutex.Release();
}
async Task ProcessFile(string filename)
{
Console.WriteLine($"Opening {filename}");
FileStream stream;
int retry = 0;
while (true)
{
try
{
stream = File.OpenRead(filename);
// do dummy work.
Console.WriteLine($"Processing {filename}");
await Task.Delay(1000);
break;
}
catch (Exception ex)
{
// I want to catch exceptions here within the context of processing this file.
if (++retry == 5)
{
throw ex;
}
Console.WriteLine($"Retry #{retry} for {filename}: {ex.Message}");
await Task.Delay(1000);
}
}
if (stream != null)
{
stream.Dispose();
}
Console.WriteLine($"Closed {filename}");
}
}
var queue = new FileQueueTest();
await queue.Start();
var files = new string[]
{
#"C:\Work\test1.txt",
#"C:\Work\test2.txt",
#"C:\Work\test3.txt",
#"C:\Work\does_not_exist.txt"
};
// simulate randomly queueing files in the background.
foreach (var file in files)
{
await Task.Delay(new Random().Next(50, 1000));
await queue.QueueFile(file);
}
Program output:
Opening C:\Work\test1.txt
Processing C:\Work\test1.txt
Opening C:\Work\test2.txt
Processing C:\Work\test2.txt
Closed C:\Work\test1.txt
Opening C:\Work\test3.txt
Processing C:\Work\test3.txt
Closed C:\Work\test2.txt
Opening C:\Work\does_not_exist.txt
Exception thrown: 'System.IO.FileNotFoundException' in mscorlib.dll
Could not find file 'C:\Work\does_not_exist.txt'.
Unhandled exception in Visual Studio
As #DavidL pointed out, the issue was due to my Visual Studio exception settings. After unchecking Break when this exception type is thrown, the exception is now handled correctly. I also confirmed it's working by running the program outside Visual Studio. See the screenshot below.
If you experience this in the future, be sure to double-check your Exception Settings for the type of exception that's breaking your app.
So I'm listening to an Server side event with my code to just write it on the console (for now) but it seems that this is making my window's form UI freeze
The code in question (which I'm calling from the main form's function)
static async Task hello()
{
HttpClient client = new HttpClient();
//client.Timeout = TimeSpan.FromSeconds(5);
while (true)
{
try
{
Console.WriteLine("Establishing connection");
using (var streamReader = new StreamReader(await client.GetStreamAsync(url)))
{
while (!streamReader.EndOfStream)
{
var message = await streamReader.ReadLineAsync();
Console.WriteLine(message.ToString());
}
}
}
catch (Exception ex)
{
//Here you can check for
//specific types of errors before continuing
//Since this is a simple example, i'm always going to retry
Console.WriteLine($"Error: {ex.Message}");
Console.WriteLine("Retrying in 5 seconds");
await Task.Delay(TimeSpan.FromSeconds(5));
}
}
}
Thanks in advance
I've solved the problem, it appears that async/await task freezes the GUI. To stop this from happening you need to use Task.Run(() => your_function()); when you call an async function
This question might be a possible duplicate of: GUI freezes when using async/await ... so go there if you want to find a bit more knowledge about the subject
im trying to Reading/Writing Async Files for an Universal App in c#.
When i write and read a file for first time, it works... But when i retry it immeadiatly, there are two Errors: 1. UnauthorizedAccess 2. Handle with the OPLOCK has been closed
It seems that the methods arent finished yet and so the data is not free
(in my frame is a button which adds a new member to a List, then the list shall serialized in an XML data. When i reNavigate to that page, that XML sheet shall be deserialized back to that List, because the Content shall be displayed)
List<Immobilie> immoListe = new List<Immobilie>();
private const string FileName_ImmoObjects = "ImmoObjects.xml";
StorageFolder sFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
IStorageFile latestImmoListFile;
public Startmenue()
{
this.InitializeComponent();
immoListe.Add(new Immobilie()); // for testing creating an XML first
immoListe[0].adresse = "Foo1";
immoListe.Add(new Immobilie());
immoListe[1].adresse = "Foo2";
WriteImmoListAsync();
ReadImmoListAsync(); // These two steps working
WriteImmoListAsync(); // everything more causes error
ReadImmoListAsync();
}
public async void WriteImmoListAsync()
{
try
{
IStorageFolder folder = await sFolder.CreateFolderAsync("Saves", CreationCollisionOption.OpenIfExists);
latestImmoListFile = await folder.CreateFileAsync(FileName_ImmoObjects, CreationCollisionOption.ReplaceExisting);
using (IRandomAccessStream stream = await latestImmoListFile.OpenAsync(FileAccessMode.ReadWrite))
using (Stream outputStream = stream.AsStreamForWrite())
{
DataContractSerializer serializer = new DataContractSerializer(typeof(List<Immobilie>));
serializer.WriteObject(outputStream, immoListe);
}
}
catch (Exception e)
{
var d = new MessageDialog(e.ToString());
await d.ShowAsync();
}
}
public async void ReadImmoListAsync()
{
int i = 0;
try
{
IStorageFolder folder = await sFolder.GetFolderAsync("Saves");
i = 1;
latestImmoListFile = await folder.GetFileAsync(FileName_ImmoObjects);
i = 2;
using (IRandomAccessStream stream = await latestImmoListFile.OpenAsync(FileAccessMode.Read))
{
i = 3;
using (Stream inputStream = stream.AsStreamForRead())
{
i = 4;
DataContractSerializer deserializer = new DataContractSerializer(typeof(List<Immobilie>));
i = 5;
immoListe = (List<Immobilie>)deserializer.ReadObject(inputStream);
}
}
}
catch (Exception e)
{
var d = new MessageDialog("Fehler I = " + i + "\n" + e.ToString());
await d.ShowAsync();
}
}
So what can i do and why is it so difficult??(normal I/O is easy-peasy).-.
As I describe in my MSDN article on async best practices, you should avoid async void:
public async Task WriteImmoListAsync();
public async Task ReadImmoListAsync();
Once your methods are properly async Task, then you can await them:
await WriteImmoListAsync();
await ReadImmoListAsync();
await WriteImmoListAsync();
await ReadImmoListAsync();
You can't start the methods again until you wait for them to complete. What that above code is trying to do is to write to a file, but while that's processing, it tries to open the file and write to it while the first method call hasn't completed. You need to wait for those method calls to finish before running them again - using the await keyword would be helpful here
It might be that the process writing/reading the file are still attached to the file. You might want to take a look at this pattern for async file read/write from Microsoft:
https://msdn.microsoft.com/en-ca/library/mt674879.aspx
Also, note that if the read and write are done from differents process, you're going to have to use a mutex. Here's a great explanation on how it works:
What is a good pattern for using a Global Mutex in C#?
I'm trying to call a method from inside the Run method of a background task which among other it desirializes a xml file. The problem is that I end up in a deadlock. This is the methos that reads the file
protected async Task<Anniversaries> readFile(string fileName)
{
IStorageFile file;
Anniversaries tempAnniversaries;
file = await ApplicationData.Current.LocalFolder.GetFileAsync(fileName);
using (IRandomAccessStream stream =
await file.OpenAsync(FileAccessMode.Read))
using (Stream inputStream = stream.AsStreamForRead())
{
DataContractSerializer serializer = new DataContractSerializer(typeof(Anniversaries));
tempAnniversaries = serializer.ReadObject(inputStream) as Anniversaries;
}
return tempAnniversaries;
}
and here is the Run method
public sealed class TileUpdater : IBackgroundTask
{
GeneralAnniversariesManager generalManager = new GeneralAnniversariesManager();
Anniversaries tempAnn = new Anniversaries();
string test = "skata";
public async void Run(IBackgroundTaskInstance taskInstance)
{
DateTime curentTime = new DateTime();
var defferal = taskInstance.GetDeferral();
await generalManager.InitializeAnniversariesAsync().AsAsyncAction();
curentTime = DateTime.Now;
var updater = TileUpdateManager.CreateTileUpdaterForApplication();
updater.EnableNotificationQueue(true);
updater.Clear();
for (int i = 1; i < 6; i++)
{
var tile = TileUpdateManager.GetTemplateContent(TileTemplateType.TileWide310x150BlockAndText01);
tile.GetElementsByTagName("text")[0].InnerText = test + i;
tile.GetElementsByTagName("text")[1].InnerText = curentTime.ToString();
updater.Update(new TileNotification(tile));
}
defferal.Complete();
}
I'm assuming that by deadlock you mean that the deserialization method finishes too late and your original program tries to read the data before it's finished loading.
It depends on how complicated/reliable you want your solution to be and how you're intending to use the program. The simplest way relies on the fact that the directory creation function is always 100% atomic in Windows/Unix and OSX. For example at the top of your readFile function have something like this.
Directory.CreateDirectory("lock");
Before you start parsing the results of your async action in TileUpdater, have a loop that looks like this.
while (Directory.Exists("lock"))
{
Thread.Sleep(50);
}
This assumes that everything is happening in the same directory, generally you'll want to replace "lock" with a path that leads to the user's temp directory for their version of Windows/Linux/OSX.
If you want to implement something more complicated where you're reading from a series of files while at the same time reading the deserialized output into your class, you'll want to use something like a System.Collections.Concurrent.ConcurrentQueue that allows your threads to act completely independently without blocking each other.
Incidentally I'm assuming that you know that the class Process and the function .waitfor() exists. You can spin off a thread and then at a later point, halt the main thread until the spawned thread finishes.
Actually I think I've found where the problem is. At the namespaces, I've tried a try and catch and I got an exception about using different namespaces at the datacontract serealizer. I have updated the code like this
file = await ApplicationData.Current.LocalFolder.GetFileAsync("EortologioMovingEntries.xml");
try
{
using (IRandomAccessStream stream =
await file.OpenAsync(FileAccessMode.Read))
using (Stream inputStream = stream.AsStreamForRead())
{
DataContractSerializer serializer = new DataContractSerializer(typeof(Anniversaries), "Anniversaries", "http://schemas.datacontract.org/2004/07/Eortologio.Model");
tempAnniversaries = serializer.ReadObject(inputStream) as Anniversaries;
}
}
catch (Exception ex)
{
error = ex.ToString();
tempAnniversaries.Entries.Add(new AnniversaryEntry("Ena", DateTime.Now, "skata", PriorityEnum.High));
}
I don't get any exceptions now but the tempAnniversaries returns null. Any ideas?