I am building a project and using async and await methods. Everyone says that async application are built from the ground up, so should you really have any sync methods? Should all methods you return a Task so you can use the asynchronously?
Lets take a simple example, where by i am using Sql to load data into a collection, here is some code.
This code loads data from a table using ExecuteQueryAsync method, the method GetQuery constructs the SQL, but calling GetTableColumns. Once the SQL is generated and executed, i loop through the collection and populate each object by calling GetDataFromReader.
Should my non async methods, be async? Am i thinking in too much of a sync-way of programming and missing something?
public async Task<ICollection<MyObject>> ExecuteQueryAsync(Module module, List<SqlParameter> parameters)
{
var result = new Collection<MyObject>();
var query = GetQuery(module);
using (var conn = new SqlConnection(_context.Database.Connection.ConnectionString))
{
await conn.OpenAsync();
using (var cmd = new SqlCommand(query, conn))
{
if (parameters != null)
cmd.Parameters.AddRange(parameters.ToArray());
using (var dr = await cmd.ExecuteReaderAsync())
{
while (await dr.ReadAsync())
{
result.Add(GetDataFromReader(module, dr));
}
}
}
}
return result;
}
public string GetQuery(Module module)
{
return "SELECT " + string.Join(",", GetTableColumns(module).ToArray()) + " FROM [TableA] ";
}
public List<string> GetTableColumns(Module module)
{
var columnNames = new List<string>();
// get all list fields for the module
var fields = (from a in module.Groups.SelectMany(a => a.Fields) select a).ToList();
foreach (var field in fields)
{
if (field.Type == FieldType.List) {
string query = "STUFF(";
query += "(SELECT ';' + [Value] FROM [TableB] FOR XML PATH(''))";
query += ", 1, 1, '') AS [" + field.ColumnName + "]";
columnNames.Add(query);
} else {
columnNames.Add("[" + field.ColumnName + "]");
}
}
return columnNames;
}
public MyObject GetDataFromReader(Module module, IDataReader dataReader)
{
var entity = new MyObject();
for (var i = 0; i < dataReader.FieldCount; i++)
{
object value = null;
var fieldName = dataReader.GetName(i);
if (!dataReader.IsDBNull(i))
{
value = dataReader.GetValue(i);
}
entity[fieldName] = value;
}
return entity;
}
If a method has no
asyncoperations inside it there's no benefit in making itasync. You should only haveasyncmethods where you have anasyncoperation (I/O, DB, etc.).If your application has a lot of these I/O methods and they spread throughout your code base, that's not a bad thing. But don't just add the
asynckeywords on synchronous methods.In your specific case
ExecuteQueryAsyncbenefits by being async as it allows usingawait cmd.ExecuteReaderAsync().GetTableColumnsandGetDataFromReaderseem to be CPU intensive methods and they don't fit they async-await paradigm.