-1

I'm having a small problem implementing async methods into my code as it is my first time using it. I am having trouble writing to a file, when I make the method synchronous it works fine, however, when using async - nothing happens.

Here is the code I am currently using:

static async Task WriteFile()
{
    string path = $@"C:\Users\{Environment.UserName}\FileToWrite.js";
    if (File.Exists(path))
    {
        try
        {
            string value;
            using (StreamReader reader = new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream("AsyncTest.Resources.data.txt")))
            {
                value = await reader.ReadToEndAsync();
            }
            using (StreamWriter writer = new StreamWriter(path))
            {
                await writer.WriteAsync(value);
            }
        }
        catch
        {
            Debug.WriteLine("Error writing to file.");
        }
    }
}

I am calling this method like this

await WriteFile(path);

Data in Resources.data.txt:

This is a test, the text file should contain this message.

Any help would be greatly appreciated, thank you!

awoodhead
  • 87
  • 8
wilenix31
  • 17
  • 4
  • 2
    please show at least how you call that method. – René Vogt Jun 15 '20 at 13:24
  • 2
    It would appear however you are calling this code, you aren't calling `await WriteFile(path);` – Neil Jun 15 '20 at 13:26
  • The method is being called as: `await WriteFile(path);` - the question's edit doesn't contain the `path` parameter but my original method does - same thing either way. – wilenix31 Jun 15 '20 at 13:31
  • My apologies, I am attempting to write to a .js file from the .txt file in the project's resources. – wilenix31 Jun 15 '20 at 13:40
  • Please share a [mcve] (that we can copy and paste into a console app and run **without modification**). – mjwills Jun 15 '20 at 13:41
  • "Nothing happens" is impossible. What _does_ happen? From what context do you call this code? Does the program continue after calling this method? Does it block? Is an exception thrown and don't you check the debug output? We can't help but guess given the lack of detail, read [ask] and create a [mre]. Also, your method does not accept an argument, while you claim you call it with one. Is another method called, or have you modified your actual code beyond recognition and does the code in your question not reproduce your issue? – CodeCaster Jun 15 '20 at 13:47
  • 1
    If you are testing this with a command line call the same will happen. The app exits before the await is finished. Putting a console.ReadLine() will pause the app so that the processing can finish. – Brian from state farm Jun 15 '20 at 13:50
  • @Brian what's that supposed to mean? If you have an async main, you can just await an async method and have your application exit once the await returns. – CodeCaster Jun 15 '20 at 13:52
  • It may have to do with optimization, if there is nothing to run after an await the program just exits. – Brian from state farm Jun 15 '20 at 13:59
  • 1
    As a side note, take a look at this: [async/await and opening a FileStream?](https://stackoverflow.com/questions/37041844/async-await-and-opening-a-filestream) TL;DR if you don't use a specific flag, the "asynchronous" filesystem operations are actually synchronous. – Theodor Zoulias Jun 15 '20 at 14:48

2 Answers2

0

If this is a console application, then I am guessing your Main method is not returning a Task, which means that your application will exit before the task is complete.

The await keyword will return when it acts on an incomplete Task. Usually it will return its own Task that the caller can use to wait until it's complete. But if the method is void, then it can't return anything and nothing is able to wait for it.

So if you have something like this:

public static async void Main() {
    await WriteFile(path);
}

Then as soon as the I/O request is made to the file system, WriteFile will return a Task, then the await in Main will return nothing (because Main is void) and your program will end.

If you are using at least C# 7.1, then you can return a Task from Main:

public static async Task Main() {
    await WriteFile(path);
}

And .NET knows that it needs to keep the application going until the Task is complete.

If you cannot use C# 7.1, then you are better off using synchronous code.

Gabriel Luci
  • 38,328
  • 4
  • 55
  • 84
-2

Change your method to return a condition of success. This will ensure to run through all of the code prior to function exit.

static async Task<bool> WriteFile(string path)
{
    if (File.Exists(path))
    {
        string value = "";
        try
        {
            using (StreamReader reader = new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream("AsyncTest.Resources.data.txt")))
            {
                value = await reader.ReadToEndAsync();
            }
        }
        catch
        {
            Debug.WriteLine("Error opening resource.");
            return false;
        }

        try
        {
            using (StreamWriter writer = new StreamWriter(path))
            {
                await writer.WriteAsync(value);
            }
        }
        catch
        {
            Debug.WriteLine("Error writing to file.");
            return false;
        }

        return true;
    }

    Debug.WriteLine("Error file does not exist.");

    return false;
}
Brian from state farm
  • 2,825
  • 12
  • 17