I have this method that should return only one Project object. IntelliSense is telling me to update it to return a Task<List> but then I have to change the declaration of the property (I want to confirm that only one project is being returned, hence the .Result.First() however I'm getting an error saying that Project is not awaitable.
public async Task<Project> GetProjectDataAsync(int projectId)
{
return await _db.LoadData<Project, dynamic>("dbo.Sp_Get_Project_Data_By_ProjectId",
new { projectId },
ConnectionStringName,
true).Result.First();
}
this is the call:
public Project Project { get; set; }
public async Task OnGetAsync(int projectId)
{
Project = await _db.GetProjectDataAsync(projectId);
}
If it worth noting, I'm using Dapper to connect to DB with the following definition for LoadData:
public async Task<List<T>> LoadData<T, U>(string sqlStatement, U parameters, string connectionStringName, bool isStoredProcedure = false)
{
string connectionString = _config.GetConnectionString(connectionStringName)!;
CommandType commandType = CommandType.Text;
if (isStoredProcedure == true)
{
commandType = CommandType.StoredProcedure;
}
using (IDbConnection connection = new SqlConnection(connectionString))
{
var rows = await connection.QueryAsync<T>(sqlStatement, parameters, commandType: commandType);
return rows.ToList();
}
}
CodePudding user response:
Get rid of the .Result
call. It's essentially trying to make the asynchronous operation synchronous. (And then .First()
is indeed not awaitable.)
The awaitable operation is _db.LoadData<Project, dynamic>(...)
, for example:
var data = await _db.LoadData<Project, dynamic>(
"dbo.Sp_Get_Project_Data_By_ProjectId",
new { projectId },
ConnectionStringName,
true
);
return data.First();
Or if you want to do it in one line, still await
the call to LoadData
and wrap that operation in parentheses:
return (await _db.LoadData<Project, dynamic>(
"dbo.Sp_Get_Project_Data_By_ProjectId",
new { projectId },
ConnectionStringName,
true
)).First();
CodePudding user response:
await
the result of LoadData
first and then get the first element of the list:
public async Task<Project> GetProjectDataAsync(int projectId)
{
var result = await _db.LoadData<Project, dynamic>("dbo.Sp_Get_Project_Data_By_ProjectId",
new { projectId },
ConnectionStringName,
true);
return result.First();
}
Or by wrapping awaiting of LoadData
call in parenthesis:
public async Task<Project> GetProjectDataAsync(int projectId)
{
return (await _db.LoadData<Project, dynamic>("dbo.Sp_Get_Project_Data_By_ProjectId",
new { projectId },
ConnectionStringName,
true)).First();
}
Task<TResult>.Result
should be avoided in asynchronous code (unless you are sure that task already has completed):
The result value of this
Task<TResult>
, which is of the same type as the task's type parameter.
Accessing the property's get accessor blocks the calling thread until the asynchronous operation is complete; it is equivalent to calling the Wait method.