Reading a text file and code jumps when using await - c#

I am writing an app for windows 8.1 tablet and I am trying to read data from a text file I have saved (this text file is just over 1kb). The below code I have works on some occasions but mainly fails(debugging/stepping over the code will often see it succeed).
StorageFolder folder = ApplicationData.Current.LocalFolder;
string fileName = "collections.json";
public Dictionary<string, string> masterDataObject;
private async void CallLoad()
{
await this.Load();
}
public async Task<Dictionary<string, string>> Load()
{
//create a file
var file = await folder.CreateFileAsync(fileName, CreationCollisionOption.OpenIfExists);
string fileContents = string.Empty;
if (file != null)
{
//returns a JSON string
fileContents = await FileIO.ReadTextAsync(file);//WHY DOES IT JUMP AT THIS LINE?????
}
Dictionary<string, string> customerFromJSON = JsonCrt.DeserializeObject<Dictionary<string, string>>(fileContents) ?? new Dictiy<string, string>();
masterDataObject = customerFromJSON;
return masterDataObject;
}
After stepping through the code several times I can see at the line
fileContents = await.....
it drops out of the method and continues with the rest of the code that is not in my Load() method.
I have reviewed async and await and have really tried to understand it, but my understanding leaves me confused as to why this is happening.
I was under the belief that await meant that execution would stop until you get a response from the code you are calling (obviously not).
So how should I be using async to make it work properly, or is there a better alternative than this code?
I have looked and tried many options but so had no success, any advice would be gratefully received.

it drops out of the method and continues with the rest of the code that is not in my Load() method
That's exactly what it's ment to do, yield control to the calling site until the asynchronous operation completes.
I'm assuming your problem lays with the fact your CallLoad method is async void instead of async Task, thus cannot be awaited, and that's why you're seeing it continue without waiting for the internal async IO to complete.
I was under the belief that await meant that execution would stop until you get a response from the code you are calling
That is still entirely true, if you await the async operation all the way
So how should I be using async to make it work properly?
async void is ment only for top level event handlers. If CallLoad isn't used as one, it should be async Task and awaited: await CallLoad();

What await does behind the scenes:
it creates a callback which contains the code after await
it calls into the xyzAsync() function, registering the callback.
if the asynchronous operation finishes, the callback is called.
So if you step through the code with a debugger, it will execute some other code if it hits await returning to the code after the await as soon as the asynchronous operation has finished.

Related

Tips for using async/await

I have been reading up on asynchronous programming in C# for the last few days. The reason for this is that the filepicker in UWP (necessary because I am programming for the Hololens 2 in Unity) is asynchronous. Despite many sources, i.e. 1, 2, 3, I have some understanding problems regarding the correct use and maybe experienced users here have a few tips for me.
An example of what I am trying to do:
Start of the programm:
public class SceneUIHandler : MonoBehaviour
{
openFile()
{
pickFile(); // calls await filepicker.PickSingleFileAsync();
loadData(path); // calls FileLoader.loadFile with path from filepicker for the reader
showData(); // should display the data
}
}
The Loader:
public class FileLoader:
{
async void loadFile(string path)
{
Task<StreamReader> streamReaderTask = getStreamReader(filePath);
StreamReader sr = await streamReaderTask;
// after that read file with the StreamReader...
...
}
async Task<StreamReader> getStreamReader(string path)
{
StorageFile file = await StorageFile.GetFileFromPathAsync(path);
var randomAccessStream = await file.OpenReadAsync();
Stream stream = randomAccessStream.AsStreamForRead();
StreamReader str = new StreamReader(stream);
return str;
}
}
So I get the path with the filepicker and later in the FileLoader class I call the file with the path and create a streamreader. So far everything works.
My problem is that if the creation of the reader takes longer the code stops because of await and jumps accordingly again in openFile() in SceneUIHandler after the method loadData(). But after that comes showData() and here I expect that the data is already loaded. From the tutorials I would now make openFile() async to write an await loadData() here.
If I do that I have to async one method after the other because I have to wait somewhere until the data is loaded otherwise i can't display, change, interact with the (not loaded) data. But by async + await I wait and continue in the previous method (which also relies on the data).
How or where do I have to stop, or do I have to separate the code differently when working with async so that the rest of the code flow is independent of the data?
I also get now a Cross thread invocation exception probably by creating and calling a slighty different getStreamReader(string path) method which just returns a BinaryReader instead of a StreamReader.
I also recommend reading my async best practices article. The first two best practices are still the most important.
From the tutorials I would now make openFile() async to write an await loadData() here.
The first best practice is "Avoid async void", because your code can't know when the method finishes. In other words, use async Task instead of async void, and await that method call.
If I do that I have to async one method after the other because I have to wait somewhere until the data is loaded otherwise i can't display, change, interact with the (not loaded) data. But by async + await I wait and continue in the previous method (which also relies on the data).
How or where do I have to stop, or do I have to separate the code differently when working with async so that the rest of the code flow is independent of the data?
The second best practice is "Use async all the way". It's normal to feel this is weird at first, but it is the correct procedure.
Eventually, you'll yield back to your framework. In the case of UWP/Unity, you'll have a UI at your highest level. And what you'll have to do is show some kind of "Loading..." screen (immediately and synchronously), and then update that when the asynchronous work completes. I have an article on async data binding that's written from an MVVM/WPF perspective, but the same ideas translate to any UI framework.
How or where do I have to stop, or do I have to separate the code differently when working with async so that the rest of the code flow is independent of the data?
Just from my point of view, the code that relies on the data needs to wait for the result, other code could run separately.
So something like this:
openFile()
{
// if it is a task
var tas = pickFile();
// TD
somework that not related to the file you get.
like setting UI size, change layout
textblock.text="this is the file";
textblock.background="";
//when all is done wait to get the file
string filepath = await task;
// code that needs the data
LoadAndShowData(filepath);
}

Calling async function with `function().Wait()` works, but `async function()` crashes

I'm calling a 3rd party library from my C# code, and have found that ctx.CreateSiteAsync(communicationSiteInfo).Wait(); works well, while await ctx.CreateSiteAsync(communicationSiteInfo); causes the application to crash. As .Wait() to the best of my knowledge causes the thread to block, I'm interested inn getting the await approach to work.
Here an extract from my code to put the above calls in context:
public async Task createSite(string base_url, SiteConfig siteConfig) {
using(var ctx = new OfficeDevPnP.Core.AuthenticationManager().GetAppOnlyAuthenticatedContext(base_url, this.applicationId, this.applicationSecret)) {
ctx.Load(ctx.Web, p => p.Title);
ctx.ExecuteQuery();
CommunicationSiteCollectionCreationInformation communicationSiteInfo = new CommunicationSiteCollectionCreationInformation {
Title = siteConfig.title,
Url = siteConfig.url,
SiteDesign = siteConfig.siteDesign,
Description = siteConfig.description,
Owner = siteConfig.ownerEmailAddress
};
try {
// This works: ctx.CreateSiteAsync(communicationSiteInfo).Wait();
await ctx.CreateSiteAsync(communicationSiteInfo);
} catch....
If I'm not mistaking, the function I'm calling it this one: ClientContextExtensions.cs.
I'm pretty new to C#, so perhaps the reason for the application crashing is obvious, but I can't see why the await wouldn't work, as the function I'm calling has async Task in it's definition.
EDIT: The weird thing regarding the exception is that the application simply crashes, and the catch clause is never reached. I don't know, but maybe this has something to do with threading or context or something in that the exception thrown in the async function call are not returned to the current thread. The application crashes on the await ctx.CreateSiteAsync(communicationSiteInfo); call.
EDIT 2: It looks as though I can simplify the issue at hand, but using this as an example instead:
public async Task StartMessageQueuePollAsync()
{
while (true)
{
await Task.Delay(1000).ConfigureAwait(false);
}
This causes the code to crash on await Task.Delay(1000).ConfigureAwait(false);. If is instead use Task.Delay(1000).Wait(), the code works as expected.
I see your answer, but I don't think that's the root cause. It's perfectly fine to use static async Task Main(), as long as your project is using C# 7.0 or higher (when that was introduced). If changing that (and making everything else synchronous, as you'd have to after removing async) made the symptom go away, then that means that somewhere along your call stack, you were missing an await.
For example, this works just fine:
using System;
using System.Threading.Tasks;
public class Program
{
public static async Task Main()
{
Console.WriteLine("Hello.");
await Pause();
Console.WriteLine("All done");
}
public static async Task Pause() {
await Task.Delay(1000);
Console.WriteLine("Done pausing");
}
}
But if you remove the await in Main, then the application would end before "Done pausing" is printed. This is because async methods run synchronously at first, but return at the first await that acts on an incomplete Task. (Pause() returns a Task when it hits await Task.Delay(1000) - before the waiting is completed)
So if you don't await an async method, then your code will just move on to the next line before the work is done. Sometimes you actually want this, but often not.
Since it otherwise runs synchronously, replacing the await with .Wait() would halt the thread and the method would not return, making it suddenly "work".
In your code, that means that either you weren't awaiting createSite() or weren't awaiting whatever called the method that called createSite(), etc.
Microsoft has a series of very well-written articles about asynchronous articles that are worth reading. Start here: Asynchronous programming with async and await
Thanks for the comments on my initial post. I got it working now, and believe it's because of I defined the Main method to be async, like this:
static async Task Main().

Does the following code sequence make sense in C#

I haven't used async/await very often and I'm not fully comfortable with them. I am trying to make an operation that is synchronous to be run asynchronously. Can you tell me if the following code snippet makes sense:
public static async Task<string> FileVersionAsync(string localFilePath)
{
FileVersionInfo versionInfo;
try
{
versionInfo = await Task.FromResult(FileVersionInfo.GetVersionInfo(localFilePath));
}
catch (SecurityException)
{
return "File Version Checker does not have permission to read file version";
}
catch (FileNotFoundException)
{
return "Unable to find configured file";
}
if (versionInfo.FileVersion == null)
return "N/A";
return versionInfo.FileVersion;
}
Adding Task, await and async do not make something asynchronous; they merely provide the plumbing to work with asynchronous code when it happens. In your example: it never happens asynchronously, so all you are doing is adding plumbing overhead for no benefit.
The compiler will generate a ton of extra code that will turn out to never be hit, because when it gets to the await it'll discover that the task is already complete, and will simply continue on the existing thread.
To actually be asynchronous, you need ... something that is async. This could be external IO, or could be something threading related - but note that simply jumping to another thread doesn't buy you anything: it just adds a context switch.
If there was a FileVersionInfo.GetVersionInfoAsync method, what you are doing might be worthwhile.
No it does not make sense.
The only reason to make your function async is if somewhere inside it awaits other functions that are async. In fact your compiler warns you if you forget to await somewhere.
The async-await syntax was invented as a replacement for other task functions like Task.ContinueWith, Task.FromResult, Task.FromException etc.
In this interview Eric Lippert compared async-await with a cook who has to prepare breakfast Search somewhere in the middle for async-await.
If a cook has to prepare breakfase he starts to boil water. But instead of waiting for the water to cook, he starts slicing bread, and do other things. Only after he has nothing to do anymore he starts waiting idly for the water to boil after which he makes the tea.
Similarly: if a program has to wait for an external process to perform a request, like a database query, write data to a file, get information from the internet etc. async-await makes sure that your thread doesn't wait idly. Instead your thread goes up its call stack to see if one of the callers can continue working without the result from the other process.
You'll see this in the following code:
public async Task<string> ReadTextFile()
{
StreamReader txtReader = File.OpenText(...);
// read the complete text file; don't wait until finished yet
Task<String> taskTxt = txtReader.ReadToEndAsync();
// as we didn't use await, we can continue processing:
DoSomething();
// now we need the result from the read action: await for it
// the result of await Task<TResult> is the TResult:
string importedTxt = await taskTxt;
return importedTxt;
}
Some guidelines for async-await:
Only use async-await if you call at least one other async function
instead of void return Task, instead of TResult return Task<TResult>
Only exception: the async event handler: this async function returns void
The return of await Task is void; the return of await Task<TResult> is TResult
If you don't need the result of an async function right now, and if you can do something meaningful while the task is processing: start the task by calling the async function, but don't await for it. Only await when you need the result
.
public async void Button_Clicked(object sender, EventArgs e)
{
// indicate you will do something time consuming:
this.ProgressBar1.Visible = true;
await DoSomethingTimeconsumingAsync(...);
// finished:
this.progressBar1.Visible = false;
}
This will make sure that whenever your thread has to wait something, it can do other things, and thus your GUI remains responsive.
No. There appears to be absolutely no need to make this method async, because Task.FromResult is ready immediately.

Async Deserialization call not working in C#

I am using Newtonsoft.Json for reading a json file. I am trying to make a aysnc call to the json file to read its data but unfortunately it's not returning anything. I tried without async and it works perfectly, following is my code:
public static async Task<T> LoadAsync<T>(string filePath)
{
// filePath: any json file present locally on the disk
string basePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase).Replace("file:\\", "");
string fullPath = Path.Combine(basePath, filePath);
using (var stream = File.OpenRead(fullPath))
{
var reader = new StreamReader(stream, Encoding.GetEncoding("iso-8859-1"));
var task = Task.Factory.StartNew(() => JsonConvert.DeserializeObject<T>(reader.ReadToEnd()));
var value = await task;
return value;
}
}
I tried to debug but debugger is not coming on "return value" in the above method and I am calling above method by following function:
private void GetDataFromJson()
{
var value = JsonUtilities.LoadAsync<TaxOffice>(Constant.TAXJSONINPUTFILE);
}
What can be the problem ? File is present locally on my computer.
I am trying to make a aysnc call to the json file to read its data
Do you really want to make the code asynchronously? Does the JsonUtilities class offer a synchronous version of the LoadAsync() method?
Your method is synchronous:
private void GetDataFromJson()
{
var value = JsonUtilities.LoadAsync<TaxOffice>(Constant.TAXJSONINPUTFILE);
}
It does exactly one thing: it calls LoadAsync(). It does store the return value of that method in value, but you never use value. So it's ignored. The return value of LoadAsync() is not the TaxOffice object. It's a Task that represents the work LoadAsync() is doing. Until that task is done, there's no way to get a value. But GetDataFromJson() doesn't wait for the task to be done. So if the caller expects it to be done by the time the method returns, it's going to be sorely disappointed.
How best to fix your code is unclear, as you haven't provided a good, minimal, complete code example showing what you need help with. But there are two obvious strategies you can follow:
Make the method asynchronous:
private async Task GetDataFromJson()
{
var value = await JsonUtilities.LoadAsync<TaxOffice>(Constant.TAXJSONINPUTFILE);
// presumably you do something with "value" here?
}
This is the best approach. But it will require that the caller be able to correctly deal with an asynchronous call. It will likely need to be turned into an async method as well. And its caller. And so on, until you get to the top of your call stack (e.g. an event handler method).
It's a bit of a pain to switch to async throughout your call stack, but the code will work much better if you do. Your thread (probably a UI thread) won't get stuck waiting on the operation, and you'll be all set to correctly deal with other asynchronous operations as well.
Ignore the asynchronous nature of the LoadAsync() method:
private void GetDataFromJson()
{
var value = JsonUtilities.LoadAsync<TaxOffice>(Constant.TAXJSONINPUTFILE).Result;
// presumably you do something with "value" here?
}
This is the Not Very Good™ approach. It works. But it holds up your current thread until the asynchronous operation is done, negating the entire benefit of having an asynchronous operation in the first place.

Async method won't return when called

I'm having a bad time with this. I'm trying to make a async method that returns the contents of a local file as string. This is my approach:
private static async Task<string> ReadContentsAsString(string fileName)
{
var uri = new Uri(string.Format(#"ms-appx:///{0}", fileName));
var file = await StorageFile.GetFileFromApplicationUriAsync(uri).AsTask().ConfigureAwait(false);
var stream = await file.OpenStreamForReadAsync().ConfigureAwait(false);
using (var streamReader = new StreamReader(stream))
{
return await streamReader.ReadToEndAsync();
}
}
Unfortunately, after the execution reaches the end of my method, the application waits forever. It hangs completely. It's being called at the very beginning, when the splash screen still shows (Windows Phone 8.1)
What do I miss?
I suspect that further up your call stack, your code has a call to Task.Wait or Task<T>.Result. This can cause a deadlock that I describe on my blog.
In summary, what happens is that when await is used on a task, by default it will capture the current "context" and use that context to resume the async method. In this case, the context is the UI context, which is associated with the single UI thread. If code further up the call stack is calling Wait or Result, then it's blocking the UI thread, which prevents the async method from finishing.
Your method is working as it should. I suspect that you are encountering this issue while debugging.
I also have noticed (sometimes) such a behaviour when debugging asyc method (here is a link to the question) - the program never returns from the method and just hangs - I don't know the exact reason of this. To test it just try to run your method like this - for example upon button click:
private async void firstBtn_Click(object sender, RoutedEventArgs e)
{
Debug.WriteLine("Before method");
string readValue = await ReadContentsAsString("TextFile1.txt");
Debug.WriteLine(string.Format("Read value: {0}", readValue));
}
As I've tested on device - it should work, but if I set a breakpoint inside your method - it will hang.

Categories