DapperLib / DapperAOT

Build time tools in the flavor of Dapper
Other
349 stars 19 forks source link

ExecuteScalarAsync calling stored procedure sp_set_session_context throws ArgumentNullException #109

Open El-Gor-do opened 7 months ago

El-Gor-do commented 7 months ago

Describe the bug

I am using .Net 8, Dapper 2.1.24 and Dapper.AOT 1.0.31 with SQL Server 2019 LocalDb.

I am trying to set session context variables by calling the system stored procedure sp_set_session_context - https://learn.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-set-session-context-transact-sql?view=sql-server-ver16

When calling ExecuteScalarAsync, an ArgumentNullException is thrown when using AOT but does not throw when not using AOT. The method below reproduces the bug.

[DapperAot]
public async Task SetSessionContextAsync()
{
    // instantiate connection
    string connectionString = ...
    SqlConnection conn = new SqlConnection(connectionString);

    // session context keys and values
    Dictionary<string, object?>? sessionContext = new Dictionary<string, object?>()
    {
        { "abc", 123 },
        { "def", "ghi" },
    };

    foreach (KeyValuePair<string, object?> kvp in sessionContext)
    {
        // this throws System.ArgumentNullException : Value cannot be null. (Parameter 'value')
        _ = await conn.ExecuteScalarAsync<int>("sp_set_session_context", param: new { key = kvp.Key, value = kvp.Value }, commandType: CommandType.StoredProcedure);
    }
}

Without [DapperAot] attribute or if the attribute is set to [DapperAot(false)] then ExecuteScalarAsync does not throw.

Here is the top of the stack trace excluding the calls from my test app.

CommandUtils.ThrowNull() line 86
Command`1.ExecuteScalarAsync[T](TArgs args, CancellationToken cancellationToken) line 73
Command`1.ExecuteScalarAsync[T](TArgs args, CancellationToken cancellationToken) line 77
...

Expected behavior ExecuteScalarAsync should not throw.

El-Gor-do commented 7 months ago

On further investigation, the code runs successfully with AOT if I replace ExecuteScalarAsync<int> with ExecuteAsync. It may be that my usage has been wrong all along. Even so, without AOT, ExecuteScalarAsync<int> doesn't throw in this example.