Skip to content

Microsoft.Data.SqlClient.SNI.x86.dll, version: 5.2.0.0 crashed host application #3087

Open
@xiangdguo

Description

@xiangdguo

Describe the bug

Microsoft.Data.SqlClient.SNI.x86.dll, version: 5.2.0.0 crashed hosted application. The host application BPHost runs multiple backend tasks in parallel in different app domains. Each task run will use the sample code below to retrieve data from a SQL Server database. It crashes multiple times every day randomly.

Application Error from Windows Event Log:
Faulting application name: Eclipse.BPHost.exe, version: 1.5.35.43, time stamp: 0x6740e2c0
Faulting module name: Microsoft.Data.SqlClient.SNI.x86.dll, version: 5.2.0.0, time stamp: 0x65d526aa
Exception code: 0xc0000409
Fault offset: 0x000013fb
Faulting process id: 0x62d0
Faulting application start time: 0x01db41e100d49446
Faulting application path: E:\Smartflow\Halo\SmartFlow.Halo.Agent\Services\Sky2\Eclipse\Eclipse.BPHost.exe
Faulting module path: E:\Smartflow\Halo\SmartFlow.Halo.Agent\Services\Sky2\Eclipse\DTE\Microsoft.Data.SqlClient.SNI.x86.dll
Report Id: 4dbbfafa-baf6-456b-a345-ad2f96b1c3a1

To reproduce

    public static async Task<Dictionary<string, Object>> GetColumnValuesAsync(string connectionString, string userId, SecureString password, List<string> columnNames, string tableName,
                             string whereClauseWithParameterNames, List<(string paramName, SqlDbType dataType, object paramValue, int size, byte scale, byte precision)> parameterNamesWithValues,
                             CommandBehavior commandBehavior = CommandBehavior.Default, int? commandTimeout = null, ILogger? logger = null)
    {

#if NETSTANDARD2_0 || NETSTANDARD2_1 || NETCOREAPP3_1
        _ = connectionString ?? throw new ArgumentNullException(nameof(connectionString), "GetColumnValuesAsync requires connection string");
        _ = userId ?? throw new ArgumentNullException(nameof(userId), "GetColumnValuesAsync requires UserId to access DB");
        _ = password ?? throw new ArgumentNullException(nameof(password), "GetColumnValuesAsync requires Password to access DB");
        _ = tableName ?? throw new ArgumentNullException(nameof(tableName), "GetColumnValuesAsync requires tableName");
        _ = columnNames ?? throw new ArgumentNullException(nameof(columnNames), "GetColumnValuesAsync requires columnNames");
        _ = whereClauseWithParameterNames ?? throw new ArgumentNullException(nameof(whereClauseWithParameterNames), "GetColumnValuesAsync requires whereClauseWithParameterNames");
        _ = parameterNamesWithValues ?? throw new ArgumentNullException(nameof(parameterNamesWithValues), "GetColumnValuesAsync requires parameterNamesWithValues");
#else
        ArgumentNullException.ThrowIfNull(connectionString);
        ArgumentNullException.ThrowIfNull(userId);
        ArgumentNullException.ThrowIfNull(password);
        ArgumentNullException.ThrowIfNull(tableName);
        ArgumentNullException.ThrowIfNull(columnNames);
        ArgumentNullException.ThrowIfNull(whereClauseWithParameterNames);
        ArgumentNullException.ThrowIfNull(parameterNamesWithValues);
#endif

        Dictionary<string, Object> returnDictionary = [];
        StringBuilder sb = new();
        sb.Append("SELECT ");

        foreach (string colName in columnNames)
        {
            sb.AppendFormat(CultureInfo.InvariantCulture, "{0},", colName);
        }
        sb.Length--;

        sb.AppendFormat(CultureInfo.InvariantCulture, " FROM {0} WHERE {1}", tableName, whereClauseWithParameterNames);

        string cmdText = sb.ToString();

        using (SqlConnection conn = new(connectionString) { Credential = new SqlCredential(userId, password) })
        {
            using SqlCommand cmd = new()
            {
                Connection = conn,
                CommandText = cmdText,
                // Also need to specify that this is a stored procedure command (default is Text)
                CommandType = CommandType.Text
            };

            if (commandTimeout.HasValue && commandTimeout.Value >= 0)
                cmd.CommandTimeout = commandTimeout.Value;

            if (parameterNamesWithValues != null)
            {
                foreach (var (paramName, dataType, paramValue, size, scale, precision) in parameterNamesWithValues)
                {
                    if (dataType == SqlDbType.VarChar || dataType == SqlDbType.NVarChar || dataType == SqlDbType.Char || dataType == SqlDbType.NChar || dataType == SqlDbType.Text || dataType == SqlDbType.NText)
                        cmd.Parameters.Add(new SqlParameter { SqlDbType = dataType, ParameterName = paramName, Direction = ParameterDirection.Output, Value = paramValue, Size = size });
                    else if (dataType == SqlDbType.Decimal)
                        cmd.Parameters.Add(new SqlParameter { SqlDbType = dataType, ParameterName = paramName, Direction = ParameterDirection.Output, Value = paramValue, Scale = scale, Precision = precision, });
                    else if (dataType == SqlDbType.DateTime2)
                        cmd.Parameters.Add(new SqlParameter { SqlDbType = dataType, ParameterName = paramName, Direction = ParameterDirection.Output, Value = paramValue, Scale = scale, });
                    else
                        cmd.Parameters.Add(new SqlParameter { SqlDbType = dataType, ParameterName = paramName, Direction = ParameterDirection.Input, Value = paramValue });
                }
            }
            // Create the input parameter, set the properties and add to command.

            await conn.OpenAsync().ConfigureAwait(false);
            using var reader = await cmd.ExecuteReaderAsync(commandBehavior).ConfigureAwait(false);
            await reader.ReadAsync().ConfigureAwait(false);
            returnDictionary = Enumerable.Range(0, reader.FieldCount)
                        .ToDictionary(reader.GetName, reader.GetValue);
        }
        return returnDictionary;
    }

Expected behavior

Do not crash the hosted app and let the tasks continue in next run later even there is an exception in the code.

Further technical details

Microsoft.Data.SqlClient version: 5.2.2
.NET target: .NET Framework 4.7.2,
SQL Server version: SQL Server 2017
Operating system: Windows Server 2019

Metadata

Metadata

Assignees

Labels

Bug! 🐛Issues that are bugs in the drivers we maintain.Needs More Info ℹ️Issues that have insufficient information to pursue investigationsTriage Done ✔️Issues that are triaged by dev team and are in investigation.Waiting for Customer ⏳Issues/PRs waiting for user response/action.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions