Home > OS >  Object not awaitable when returning Task<object> instead of List
Object not awaitable when returning Task<object> instead of List

Time:05-02

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.

  • Related