0

I have c# project which consists basically of the following 3 classes. It should asynchronously reads a local database (sqlite) and continue with the main process. Though it does not throw any errors, nor executes the db reading. It only executes the infinite loop contained in the main process while(true) {"Doing Stuff on the Main Thread..."}. It seems the main thread is not waiting for the asynchronous process. Thanks in advance.

class DatabaseAccessor
{
    static void Main(string[] args)
    { 
        var inq = new InquireDatabaseAsync();
        inq.DoWork();

        while (true)
        {
            Console.WriteLine("Doing Stuff on the Main Thread...");
        }
    }      
}

public class InquireDatabaseAsync
{
    public async Task DoWork()
    {
        await Task.Run(() =>
        {
            LongRunningOperation();
        });
    }

    private static async Task LongRunningOperation()
    {
        Data_connection2 dbobject = new Data_connection2();
        SQLiteConnection m_dbConnection = new SQLiteConnection();
        m_dbConnection.ConnectionString = dbobject.datalocation2();
        m_dbConnection.Open();

        string sql = "SELECT * FROM Commands WHERE Id = (SELECT MAX(Id) FROM Commands)";
        SQLiteCommand SQLcommand = new SQLiteCommand(sql, m_dbConnection);
        var instruct = await ExecuteLoopTaskAsync(SQLcommand);
    }

    public async static Task<string> ExecuteLoopTaskAsync(SQLiteCommand sqlCommand)
    {          
        while (true)
        {
            System.Threading.Thread.Sleep(1000);
            var reader = sqlCommand.ExecuteReader();
            while (reader.Read())
                Console.WriteLine("Id: " + reader["Id"] + "\tInstruction: " + reader["Instruction"] + "\tCellular: " + reader["Cellular"] + "\tTimestamp: " + reader["Timestamp"]);
        }
        return "Finished...";
    }
}

class Data_connection2
{
    public string datalocation2()
    {
        String dir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
        return "Data Source=" + dir + "\\database9.sqlite";
    }
}
Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188
ekremer
  • 311
  • 4
  • 23
  • 5
    "It seems the main thread is not waiting for the asynchronous process." Why would it? Which piece of code do you expect would make it wait? – Jon Skeet Aug 11 '15 at 15:16

4 Answers4

3

This line is returning a Task:

inq.DoWork();

But nothing is ever done with that Task object. So it launches the task asynchronously and the consuming code doesn't block on it. If you do want to block on it (and in this case you probably do), you can await the task:

inq.DoWork().Wait();

While the inner workings can be more complex than I can explain (or myself fully grasp at this time), this effectively should have the same observed behavior as having used:

await inq.DoWork();

But since the enclosing method isn't async then you can't use that syntax.


Basically consider the paradigm that things should be "async all the way down". The implication of this is that at the top level of any given stack of async calls there should be something which manages the Tasks. For technologies such as WinForms, WPF, ASP.NET, etc. there are built-in mechanisms to do this. For a console app, you're essentially much more bare-bones. The main() method is the very top level, and needs to manage the Taskss beneath it on the stack.

David
  • 208,112
  • 36
  • 198
  • 279
0

What you were probably trying to do might be,

static void Main(string[] args)
{
    var enquiry = new InquireDatabaseAsync().DoWork();
    while (!enquiry.IsCompleted)
    {
        Console.WriteLine("Doing Stuff on the Main Thread...");
    }

    // In case there were any exceptions.
    enquiry.Wait();
}      
Jodrell
  • 34,946
  • 5
  • 87
  • 124
0

Although DoWork awaits for the task internally, it returns to the caller immediately! Therefore the caller must await again if it wants to wait for the task termination before continuing.

inq.DoWork().Wait();
Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188
0

This code has several problems. Consider using something like the following:

using System;
using System.Threading.Tasks;

namespace ConsoleApplication6
{
    class DatabaseAccessor
    {
        static async void Main(string[] args)
        {
            await Task.Run(() =>
            {
                InquireDatabaseAsync.LongRunningOperation();
            });
        }
    }

    public static class InquireDatabaseAsync
    {
        public static void LongRunningOperation()
        {
            Data_connection2 dbobject = new Data_connection2();
            SQLiteConnection m_dbConnection = new SQLiteConnection();
            m_dbConnection.ConnectionString = dbobject.datalocation2();
            m_dbConnection.Open();

            string sql = "SELECT * FROM Commands WHERE Id = (SELECT MAX(Id) FROM Commands)";
            SQLiteCommand SQLcommand = new SQLiteCommand(sql, m_dbConnection);

            while (true)
            {
                System.Threading.Thread.Sleep(1000);
                var reader = sqlCommand.ExecuteReader();
                while (reader.Read())
                    Console.WriteLine("Id: " + reader["Id"] + "\tInstruction: " + reader["Instruction"] + "\tCellular: " + reader["Cellular"] + "\tTimestamp: " + reader["Timestamp"]);
                break;
            }
            Console.WriteLine("Finished.");
        }
    }

    class Data_connection2
    {
        public string datalocation2()
        {
            String dir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            return "Data Source=" + dir + "\\database9.sqlite";
        }
    }
}
Jeff Prince
  • 658
  • 6
  • 13
  • Sorry, I wasn't able to compile this code because of the SQLite stuff. I hadn't realized that you can't have an async main method. Anyway, the techniques are similar to do what you want to do. This is discussed at http://stackoverflow.com/questions/9208921/async-on-main-method-of-console-app. – Jeff Prince Aug 11 '15 at 16:00