AwonDanag
AwonDanag

Reputation: 329

How to properly catch asynchronous task?

I was wondering why the exception in this Click event is not being caught? Nothing fancy in the code, except for statusLabel displaying the status of the process to the user. myDataTable is a local variable; the goal is to assign the result to it.

Does GetDataTable have to be asynchronous as well?

public DataTable GetDataTable(string connectionString, string cmdText)
{
    DataTable dt = new DataTable();
    using (SqlConnection conn = new SqlConnection(connectionString)) {
        using (SqlCommand comm = new SqlCommand(cmdText, conn)) {
            conn.Open();
            dt.Load(comm.ExecuteReader);
            return dt;
        }
    }
}

private async void Button1_Click(object sender, EventArgs e)
{
    try {
        statusLabel.Text = "Processing...";

        Task<DataTable> dtTask = Task.Run(() => GetDataTable(connectionString, commandText));
        await dtTask;
        myDataTable = dtTask.Result;

        statusLabel.Text = "Done!";
    } catch (Exception ex) {
        MessageBox.Show("Error");
    }
}

UPDATE

I managed to do solve this problem by making GetDataTable() return a Task of DataTable and changing both .Open and .ExecuteReader to their asynchronous counterparts. For the other method, those three lines inside the Try block I reduced to one:

myDataTable = await GetDataTable(connectionString, commandText);

Thanks to everyone's patiences!

Upvotes: 2

Views: 256

Answers (2)

Panagiotis Kanavos
Panagiotis Kanavos

Reputation: 131219

Instead of using Task.Run to convert a synchronous method to an asynchronous one, use ExecuteReaderAsync to truly load data asynchronously. After that, your code becomes a lot simpler:

public async Task<DataTable> GetDataTable(string connectionString, string cmdText)
{
    DataTable dt = new DataTable();
    using (SqlConnection conn = new SqlConnection(connectionString)) {
        using (SqlCommand comm = new SqlCommand(cmdText, conn)) {
            conn.Open();
            var reader=await comm.ExecuteReaderAsync();
            dt.Load(reader);
            return dt;
        }
    }
}

private async void Button1_Click(object sender, EventArgs e)
{
    try {
        statusLabel.Text = "Processing...";

        myDataTable = await GetDataTable(connectionString, commandText);

        statusLabel.Text = "Done!";
    } catch (Exception ex) {
        MessageBox.Show("Error");
    }
}

GetDataTable became an asynchronous method that executes the query asynchronously and returns a reader with:

var reader=await comm.ExecuteReaderAsync();
dt.Load(reader);
return dt;

After that, setting the myDataTable variable only requires using an await:

myDataTable = await GetDataTable(connectionString, commandText);

Upvotes: 1

karmasponge
karmasponge

Reputation: 1367

I believe the answer you are looking for is here: Async void exception handling

I'm assuming that the 'Button1_Click' method was meant to be 'async void'?:

private async void Button1_Click(object sender, EventArgs e)
{
    ...
}

Upvotes: 0

Related Questions