locked
How not async code in Windows Store app? RRS feed

  • Question

  • I'm new to Windows Store dev and all this "async" and "await" stuff.  The code below is sometimes "breezed over" or something where it doesn't run.  And then I'll have a function after it that is depending on it having first completed (i.e. in sync).

    I tried simply removing "async" and "await" but it doesn't seem to like that.  What's the normal protocol here, please?

    private async void EnsureOrCreateLocalFiles()
    {
        await KnownFolders.DocumentsLibrary.CreateFileAsync("myfile.txt");
    }


    Thanks.

    Tuesday, September 10, 2013 5:30 PM

Answers

  • I'd return a Task from the method instead of void, and to await the call to this method in the caller.

    private async Task EnsureOrCreateLocalFiles()
    {
        await KnownFolders.DocumentsLibrary.CreateFileAsync("myfile.txt");
    }

    • Marked as answer by fiverc Tuesday, September 10, 2013 7:36 PM
    Tuesday, September 10, 2013 6:34 PM

All replies

  • I'd return a Task from the method instead of void, and to await the call to this method in the caller.

    private async Task EnsureOrCreateLocalFiles()
    {
        await KnownFolders.DocumentsLibrary.CreateFileAsync("myfile.txt");
    }

    • Marked as answer by fiverc Tuesday, September 10, 2013 7:36 PM
    Tuesday, September 10, 2013 6:34 PM
  • As Ben already wrote, you should make this method a Task. The guidelines also state that awaitable methods should be named '...Async'.

    This would make your method look like this:

    private async Task EnsureOrCreateLocalFilesAsync()
     {
         await KnownFolders.DocumentsLibrary.CreateFileAsync("myfile.txt");
     }

    Then you can either wait for this method to complete (as if it was synchronous) or call it asynchronously without waiting for it:

    //prepare the file await EnsureOrCreateLocalFilesAsync(); //write to the file await WriteToFileAsync(); //prepare but don't wait Task prepare = EnsureOrCreateLocalFilesAsync();

    //this will continue immediately

    //but you can await it later...

    await prepare;

    Note that even if you don't want to wait for the Task, you should always catch the result with Task .. = ... or you would miss exceptions happening!

    Also note that CreateFileAsync(...) actually returns a StorageFile (and can fail too).

    cheers,

    michael


    Life is unsure - always eat the dessert first!


    Tuesday, September 10, 2013 9:28 PM
  • I'd like to add more to coojbs answer. His answer was correct when he told you how to fix it, but he didn't tell you WHY it fixed it.  When you mark a method with the Async keyword, you have two types of return values. You can return a task, or you can return void. If you return a task, the compiler can use the task to inspect any returns, exceptions etc. In other words, if you return a Task, the compiler cares about what happened in the asynchronous method.  If you return a void, then there is nothing for the compiler to look at. In other words, you've told the compiler that you aren't returning anything at all, and thus the compiler does not care what happened. In this case, the compiler treats your method as a "fire and forget", and it will simply execute the method and continue to the next.

    Since your typed your method as

    private async void EnsureOrCreateLocalFiles()

    The compiler does a "fire and forget" on the EnsureOrCreateLocalFiles() and immediately moves on to the next method. And thus, any code afterwards should NOT depend on EnsureOrCreateLocalFile(). If you want that code to care about the result of EnsureOrCreateLocalFile(), then you need to type it as returning a Task, and not a void.

    One other note, there is a bug in your code. If "myfile.txt" exists, then you will get an exeption. Since you typed this as void, the compiler will not know that an exception occurred (because it did a "fire and forget"). Thus, you will get sporadic behavior. In you case, you use use the CreationCollisionOption flag to prevent this

    .. CreateFileAsync("myfile.txt", CreationCollisionOption.ReplaceExisting);

    This small change will overwrite "myfile.txt" if it exists, and thus not throw any exception.

    • Proposed as answer by DPinTX Thursday, January 9, 2014 7:13 PM
    Thursday, January 9, 2014 7:13 PM