I'm working on a large project that runs on .NET 4.0. This framework uses ADO.NET for database calls and we're currently adding asynchronous API methods. The SqlCommand
class has the APM methods SqlCommand.BeginExecuteReader()
and SqlCommand.EndExecuteReader()
, but SqlDataReader
does not have asynchronous implementations.
When the SqlCommand.ExecuteReader()
is finished I want to iterate through the results using SqlDataReader
. Microsoft introduces asynchronous methods for SqlDataReader
in .NET 4.5, so I can't use those in 4.0.
Question: Should we upgrade to be able to use the asynchronous (TAP) methods of SqlDataReader
?
If we do, why?
I searched the web and stackoverflow alot for answers, but I only seem to find implementations for this. It doesn't tell me what benefit those new implementations give.
Here we use the asynchronous methods of SqlCommand
, but we can't use the new asynchronous methods for SqlDataReader
, like SqlDataReader.ReadAsync()
.
private Task<IDataReader> ExecuteReaderAsync(IDbCommand dbCommand)
{
var sqlCommand = CheckIfSqlCommand(dbCommand);
PrepareExecuteReader(dbCommand);
return Task<IDataReader>
.Factory
.FromAsync(sqlCommand.BeginExecuteReader, sqlCommand.EndExecuteReader, null);
}
private void ReadAll(Task<IDataReader> readerTask)
{
var reader = readerTask.Result;
while (reader.Read()) // Should this be asynchronously?
{
// Do something
}
}
public Task<IDataReader> Foo(IDbCommand dbCommand) {
return ExecuteReaderAsync(dbCommand)
.ContinueWith(readerTask => ReadAll(readerTask));
}
In .NET 4.5 we can use the async/await keywords, and we can use the new asynchronous methods for SqlDataReader
, like SqlDataReader.ReadAsync()
.
private async Task<SqlDataReader> ExecuteReaderAsync(SqlCommand dbCommand)
{
PrepareExecuteReader(dbCommand);
return await dbCommand.ExecuteReaderAsync();
}
private async Task ReadAll(SqlDataReader reader)
{
while (await reader.ReadAsync()) // Should this be asynchronously?
{
// Do something
}
}
public async Task<IDataReader> Foo(SqlCommand dbCommand)
{
var reader = await ExecuteReaderAsync(dbCommand);
await ReadAll(reader);
return reader;
}
The theoretical benefit is that your application will use fewer threads, therefore consuming less memory and CPU resources on thread overhead. That, in turn, leaves more resources available for your application or other system activities, improving the performance and scalability of the application.
For applications that receive a lot of simultaneous requests the benefit can be significant. You can only find the actual difference that you would see by testing your specific application, though. This is a nice article that digs in to details.
My opinion is that if you don't find the async DataReader code to be harder to understand, read, and debug then go ahead and use it. It will be consistent with how you handle Command code and async is generally considered a modern best practice. What do you have to lose?
I do want to mention, however, that you should really consider using a higher-level API, i.e., an ORM. I think that Entity Framework and nHibernate are the most popular for .NET currently. EF6 has built-in async support and for a typical query to be async you can simply use something like ToListAsync(). See this for a start.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With