{"record":{"id":"95ef9b5e80f4be0f","repo":"DapperLib/Dapper","slug":"async-operations-require-use-of-a-dbconnection-or-95ef9b","errorCode":null,"errorMessage":"Async operations require use of a DbConnection or an IDbConnection where .CreateCommand() returns a DbCommand","messagePattern":"Async operations require use of a DbConnection or an IDbConnection where \\.CreateCommand\\(\\) returns a DbCommand","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"Dapper/SqlMapper.Async.cs","lineNumber":418,"sourceCode":"            }\r\n            else\r\n            {\r\n                throw new InvalidOperationException(\"Async operations require use of a DbConnection or an already-open IDbConnection\");\r\n            }\r\n        }\r\n\r\n        /// <summary>\r\n        /// Attempts setup a <see cref=\"DbCommand\"/> on a <see cref=\"DbConnection\"/>, with a better error message for unsupported usages.\r\n        /// </summary>\r\n        private static DbCommand TrySetupAsyncCommand(this CommandDefinition command, IDbConnection cnn, Action<IDbCommand, object?>? paramReader)\r\n        {\r\n            if (command.SetupCommand(cnn, paramReader) is DbCommand dbCommand)\r\n            {\r\n                return dbCommand;\r\n            }\r\n            else\r\n            {\r\n                throw new InvalidOperationException(\"Async operations require use of a DbConnection or an IDbConnection where .CreateCommand() returns a DbCommand\");\r\n            }\r\n        }\r\n\r\n        private static async Task<IEnumerable<T>> QueryAsync<T>(this IDbConnection cnn, Type effectiveType, CommandDefinition command)\r\n        {\r\n            object? param = command.Parameters;\r\n            var identity = new Identity(command.CommandText, command.CommandTypeDirect, cnn, effectiveType, param?.GetType());\r\n            var info = GetCacheInfo(identity, param, command.AddToCache);\r\n            bool wasClosed = cnn.State == ConnectionState.Closed;\r\n            var cancel = command.CancellationToken;\r\n            using var cmd = command.TrySetupAsyncCommand(cnn, info.ParamReader);\r\n            DbDataReader? reader = null;\r\n            try\r\n            {\r\n                if (wasClosed) await cnn.TryOpenAsync(cancel).ConfigureAwait(false);\r\n                reader = await ExecuteReaderWithFlagsFallbackAsync(cmd, wasClosed, CommandBehavior.SequentialAccess | CommandBehavior.SingleResult, cancel).ConfigureAwait(false);\r\n\r\n                var tuple = info.Deserializer;\r","sourceCodeStart":400,"sourceCodeEnd":436,"githubUrl":"https://github.com/DapperLib/Dapper/blob/72a54c475f75e18cb93cba0809d00a5e6e49efd9/Dapper/SqlMapper.Async.cs#L400-L436","documentation":"TrySetupAsyncCommand throws InvalidOperationException(\"Async operations require use of a DbConnection or an IDbConnection where .CreateCommand() returns a DbCommand\") when the command built via SetupCommand is not a DbCommand. Dapper's async execution needs DbCommand for ExecuteReaderAsync etc.; a connection whose CreateCommand yields a plain IDbCommand cannot drive async I/O. The message is an intentional, clearer replacement for an InvalidCastException.","triggerScenarios":"Using an async Dapper API with a connection whose CreateCommand() returns a custom IDbCommand that is not a DbCommand (legacy provider or a mock IDbConnection.CreateCommand returning a stub IDbCommand).","commonSituations":"Unit tests mocking IDbConnection.CreateCommand to return a non-DbCommand stub; a legacy ADO.NET provider that does not derive its command from DbConnection/DbCommand.","solutions":["Use a standard provider whose command derives from System.Data.Common.DbCommand (all mainstream providers do).","In tests, mock DbConnection/DbCommand rather than the raw IDb* interfaces, or use an in-memory provider like Microsoft.Data.Sqlite."],"exampleFix":"// before (test mock)\nvar mockConn = Substitute.For<IDbConnection>();\nmockConn.CreateCommand().Returns(mockCmd); // mockCmd is IDbCommand\nawait mockConn.QueryAsync<T>(sql); // throws\n\n// after\nvar mockConn = Substitute.For<DbConnection>();\n// provide DbCommand-derived mock; or use a real in-memory provider","handlingStrategy":"type-guard","validationCode":"if (cnn is not System.Data.Common.DbConnection || cnn.CreateCommand() is not System.Data.Common.DbCommand)\n    throw new InvalidOperationException(\"Async Dapper requires a connection whose CreateCommand returns a DbCommand.\");","typeGuard":"static bool HasDbCommand(IDbConnection c) => c.CreateCommand() is System.Data.Common.DbCommand;","tryCatchPattern":"try { await cnn.QueryAsync<T>(sql); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"returns a DbCommand\"))\n{ /* use a provider whose command derives from DbCommand */ }","preventionTips":["Avoid mocking the raw IDb* interfaces for async tests; use DbConnection/DbCommand or a real provider.","Confirm legacy providers derive their command types from System.Data.Common.DbCommand before using async APIs."],"tags":["async","connection","command","invalid-operation","ado-net"],"backgroundTag":null,"analyzedSha":"72a54c475f75e18cb93cba0809d00a5e6e49efd9","analyzedAt":"2026-08-13T14:18:18.115Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}