FP S6966: Do not suggest async methods for SqlDataReader.IsDBNull/GetFieldValue

  • What language is this for? C#

  • Which rule? S6966: Awaitable method should be used

  • Why do you believe it’s a false-positive/false-negative? Microsoft’s suggested best practices for SqlDataReader are that the non-async methods should be used unless the SqlDataReader was created using a CommandBehavior value of SequentialAccess.

    When the SequentialAccess flag is not used, then the entire row will be retrieved from the server and made available in local memory by the ReadAsync() call. IsDBNullAsync and GetFieldValueAsync will never await, so using them just adds overhead. The async methods should not be used in this case (the default for SqlDataReader).

    This definitely applies to both the methods on both System.Data.SqlClient.SqlDataReader and Microsoft.Data.SqlClient.SqlDataReader. It should apply to any DbDataReader subclass:

If sequential mode isn’t specified, all column values should become available in memory each time ReadAsync completes, and calling the synchronous version of the method shouldn’t block the calling thread.

  • Are you using
    • SonarQube Community Build v26.3.0.120487
    • SonarQube for Visual Studio 9.9.0.16418, in connected mode
  • How can we reproduce the problem?
using Microsoft.Data.SqlClient;
using System.Threading.Tasks;

namespace SonarQubeRepros
{
    internal sealed class S6966FalsePositiveRepoSqlClientAsync
    {
        public static async Task<string> GetValueAsync()
        {
            using (var connection = new SqlConnection())
            {
                using (var cmd = new SqlCommand("SELECT * FROM sys.tables", connection))
                {
                    await connection.OpenAsync();
                    using (var reader = await cmd.ExecuteReaderAsync())
                    {
                        while (await reader.ReadAsync())
                        {
                            var ordinal = reader.GetOrdinal("name");
                            if (!reader.IsDBNull(ordinal))
                            {
                                return reader.GetFieldValue<string>(ordinal);
                            }
                        }
                    }
                }
            }

            return null;
        }
    }
}

Both the IsDBNull and GetFieldValue calls are detected by S6966.

Hello @HamsterExAstris
I confirm this is an FP.
I’ll add it to our backlog to fix in a future sprint (internal only).

Best
Mary

1 Like