1

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();
            }
        }

2 Answers 2

3

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();
Sign up to request clarification or add additional context in comments.

Comments

3

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.