I keep seeing QueryAsync and ExecuteAsync everywhere, but I'm not 100% sure when to actually await them inside a controller action. If I fire off multiple Dapper calls in parallel using Task.WhenAll, do I need to worry about thread-safety or connection leaks?
Specifically, I have a controller that fetches a user profile and their recent orders in one request. My first attempt looks like this:
public async Task<IActionResult> GetProfile(int userId)
{
// Open connection manually — is this okay?
using var conn = new SqlConnection(_connectionString);
await conn.OpenAsync();
var profileTask = conn.QueryFirstOrDefaultAsync<User>(
"SELECT * FROM Users WHERE Id = @Id",
new { Id = userId });
var ordersTask = conn.QueryAsync<Order>(
"SELECT * FROM Orders WHERE UserId = @Id",
new { Id = userId });
await Task.WhenAll(profileTask, ordersTask);
return Ok(new { Profile = profileTask.Result, Orders = ordersTask.Result });
}
I know mixing .Result with await is usually a bad idea, but I'm not sure how to restructure this cleanly. Should I be opening the connection per-query, or is a single Scoped connection better? Any advice on avoiding deadlocks or connection exhaustion under concurrent load would be appreciated.
Can you answer this question?
Write Answer0 Answers