Search code examples
c#sql-servertimeouttasknunit

NUnit - SqlConnection timeout within Task


I'm having this weird issue (or I think my brain is burned..). While I run this code from outside a Task, it works fine, but when I run within a Task.Run(() => ...), I get a SqlException timeout:

public static Item GetItemById(int id)
{
    Item result;

    using (var conn = App.DbFactory.CreateConnection())
    {
         result = _repository.GetById(id, conn) ?? throw new ElementNotFoundException();
    }
    
    return result;
}

// _repository.GetById
public Item GetById(int id, IDatabaseConnection conn)
{
     Item result;
        
     var cmd = conn.CreateCommand();
     cmd.CommandText = "QUERY COMMAND";

     using (var dr = cmd.ExecuteReader()) <-- EXCEPTION
     {
          result = dr.Read() ? Create(dr) : null;
     }

     return result;
}


// Method that works.
public static Item GetItemTest()
{
    return GetItemById(12);
}

// Method that doesn't work.
public static async Item GetItemAsyncTest()
{
    return await Task.Run(() => GetItemById(12));
}

App.DbFactory.CreateConnection() returns IDbConnection.

Update: The exception is thrown when executing the DbCommand (ExecuteReader).

The GeyById method only calls a repository method (raw TSQL query). The caller method is supposed to read each item from the database from a foreach (using Task/async/await, no more than 5 concurrent connections). At this point, I don't know if I'm doing something wrong or if I'm missing some concept.

I'm using .NET Framework 4.5 and SQL Server 2012.

Temp solution: Ok, I'd wasted almost 6hs trying to figure out what was wrong...and it was NUnit. When running GetItemAsyncTest() from a Test, it throws the timeout exception. Running the same async method from a Controller works like a charm.

I'm googling about this thing. If anyone had the same issue, I'll be glad to know what it is :)

Thanks!!


Solution

  • Well, finally solved! It was a workaround between NUnit and TransactionScope. Testing an async method that hits the database using a TransactionScope (to keep the database clean) causes a timeout exception when executing the command.

    The way to solve this issue was: upgrade to NET Framework 4.5.1 and add TransactionScopeAsyncFlowOption.Enabled to the TransactionScope constructor.