Reputation: 169
Below is the code I am using. Intended to make it an asynchronous call to time consuming function.
async Task<DataSet> GetDataAsync()
{
System.Threading.Thread.Sleep(5000);
SqlDataAdapter adpator = new SqlDataAdapter("Select * from table1;select * from table2;select * from table3;select * from table4"
, @"Data Source=ANKIT\SQLEXPRESS;Initial Catalog=IM_DB;Integrated Security=True");
DataSet ds = new DataSet();
adpator.Fill(ds);
return ds;
}
protected async void btnFillData_Click(object sender, EventArgs e)
{
lblStatus.Text = "Going to run a blocking thread....";
Task<DataSet> dsAsync = GetDataAsync();
lblStatus.Text = "Going to await the same......";
DataSet ds = await dsAsync;
lblStatus.Text = "released from await";
gvIngredient.DataSource = ds.Tables[0];
gvIngredient.DataBind();
}
Function GetDataAsync working as a synchronous call. I want it to be asynchronous as it is having a database call to fetch thousands of records which is time consuming.
There is something that I missed in the async model on asp.net.
Upvotes: 1
Views: 302
Reputation: 457302
Function GetDataAsync working as a synchronous call.
Yes. In fact, there is a compiler warning that will tell you GetDataAsync
will run synchronously.
It is possible to make it asynchronous, but not using the DataSet.Fill
approach. That is a Very Old way of doing things, and was not updated to use the new asynchronous APIs. You'd have to use something like Entity Framework 6 or asynchronous DbCommands.
But before you head down that path...
protected async void btnFillData_Click(object sender, EventArgs e)
{
lblStatus.Text = "Going to run a blocking thread....";
Task<DataSet> dsAsync = GetDataAsync();
lblStatus.Text = "Going to await the same......";
DataSet ds = await dsAsync;
lblStatus.Text = "released from await";
gvIngredient.DataSource = ds.Tables[0];
gvIngredient.DataBind();
}
This code shows a misunderstanding of how ASP.NET works. When the button is clicked, there is a single HTTP request sent to the ASP.NET server, and the server can only send a single HTTP response. This response is only sent at the end of the click event method. So, setting lblStatus.Text
multiple times won't have any effect - only the last update will be seen by the user.
Put another way, await
on ASP.NET only yields to the ASP.NET runtime; it does not yield to the client (browser). The HTTP response is not sent until all await
s have completed.
So, what you're really asking is how to start a long-running operation in ASP.NET and then have the client update later with progress or completion information. For this you'll need a different technology, such as SignalR, AJAX, or UpdatePanel
.
Upvotes: 0
Reputation: 2343
The first problem:
The modifier async
doesn't make your method asynchronous, it just gives you an opportunity to use the await
keyword inside. Thus, the function GetDataAsync
is not asynchronous - it uses the same thread which it has been called. To make this function asynchronous you have to use the Task
class and the StartNew
method like this:
Task<DataSet> GetDataAsync()
{
Function<DataSet> func = () =>
{
System.Threading.Thread.Sleep(5000);
SqlDataAdapter adpator = new SqlDataAdapter("Select * from table1;select * from table2;select * from table3;select * from table4"
, @"Data Source=ANKIT\SQLEXPRESS;Initial Catalog=IM_DB;Integrated Security=True");
DataSet ds = new DataSet();
adpator.Fill(ds);
return ds;
};
return Task.Factory.StartNew(func);
}
Check this really useful article up to understand how async\await
works.
The second:
Your code keeps the SqlDataAdapter
in the memory after each call of the GetDataAsync
. This behavior leads to the memory leaks. You'd better use the using
statement:
DataSet ds = new DataSet();
using(var adapter = new SqlDataAdapter(query, connectionString))
adapter.Fill(ds);
Hope this helps.
Upvotes: 2