Como faço para SqlDataReader.ReadAsync () ser executado de forma assíncrona?

Ao fazer chamadas para o SQL Server que realmente fazem coisas que levam tempo,SqlDataReader.ReadAsync() corre de forma síncrona para mim. Existe alguma maneira de forçá-lo a executar de forma assíncrona ou é minha única opção para chamá-loTask.Run()?

Aqui está uma reprodução. Ele usa winforms para demonstrar que a chamada bloqueia o thread da GUI. Observe que o T-SQL realmente precisa fazer alguma coisa -isso não é reproduzível comWAITFOR DELAY '00:00:20'.

using System;
using System.Configuration;
using System.Data.Common;
using System.Data.SqlClient;
using System.Threading.Tasks;
using System.Windows.Forms;

static class SqlDataReaderReadAsyncProgram
{
    static async void Form_Shown(object sender, EventArgs e)
    {
        var form = (Form)sender;
        // Declare your connection string in app.config like
        // <connectionStrings><remove name="LocalSqlServer"/><add name="LocalSqlServer" connectionString="Data Source=localhost\SQLEXPRESS;Integrated Security=true"/></connectionStrings>
        using (DbConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings[0].ConnectionString))
        {
            form.Text = "connecting…";
            await connection.OpenAsync();
            form.Text = "connected!";
            // Install a stored procedure.
            using (var command = connection.CreateCommand())
            {
                command.CommandText = "SET NOCOUNT ON"
                    + " SELECT 'a'"
                    + " DECLARE @t DATETIME = SYSDATETIME()"
                    + " WHILE DATEDIFF(s, @t, SYSDATETIME()) < 20 BEGIN"
                    + "   SELECT 2 x INTO #y"
                    + "   DROP TABLE #y"
                    + " END"
                    + " SELECT 'b'";
                form.Text = "executing…";
                using (var reader = await command.ExecuteReaderAsync())
                {
                    form.Text = "reading…";
                    do
                    {
                        // Blocks on the second call until the second resultset is returned by SQL Server
                        while (await reader.ReadAsync())
                        {
                        }
                    } while (await reader.NextResultAsync());
                    form.Text = "done!";
                }
            }
        }
        await Task.Delay(TimeSpan.FromSeconds(5));
        form.Close();
    }

    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        var form = new Form();
        form.Shown += Form_Shown;
        Application.Run(form);
    }
}

Quando executo isso, a janela fica "(Não está respondendo)" por 20 segundos antes de o relatório ser concluído (observe que, ao depurar no VS, o texto "(Não está respondendo)" não aparece, mas ainda congela). Se eu depurar no VS e o interromper enquanto estiver congelado, eu o vejo sentado com uma pilha de chamadas com a seguinte aparência:

    [Managed to Native Transition]  
    System.Data.dll!SNINativeMethodWrapper.SNIReadSyncOverAsync(System.Runtime.InteropServices.SafeHandle pConn, ref System.IntPtr packet, int timeout) Unknown
    System.Data.dll!System.Data.SqlClient.TdsParserStateObject.ReadSniSyncOverAsync()   Unknown
    System.Data.dll!System.Data.SqlClient.TdsParserStateObject.TryReadNetworkPacket()   Unknown
    System.Data.dll!System.Data.SqlClient.TdsParserStateObject.TryPrepareBuffer()   Unknown
    System.Data.dll!System.Data.SqlClient.TdsParserStateObject.TryReadByteArray(byte[] buff, int offset, int len, out int totalRead)    Unknown
    System.Data.dll!System.Data.SqlClient.TdsParserStateObject.TryReadInt64(out long value) Unknown
    System.Data.dll!System.Data.SqlClient.TdsParser.TryProcessDone(System.Data.SqlClient.SqlCommand cmd, System.Data.SqlClient.SqlDataReader reader, ref System.Data.SqlClient.RunBehavior run, System.Data.SqlClient.TdsParserStateObject stateObj)    Unknown
    System.Data.dll!System.Data.SqlClient.TdsParser.TryRun(System.Data.SqlClient.RunBehavior runBehavior, System.Data.SqlClient.SqlCommand cmdHandler, System.Data.SqlClient.SqlDataReader dataStream, System.Data.SqlClient.BulkCopySimpleResultSet bulkCopyHandler, System.Data.SqlClient.TdsParserStateObject stateObj, out bool dataReady)  Unknown
    System.Data.dll!System.Data.SqlClient.SqlDataReader.TryHasMoreRows(out bool moreRows)   Unknown
    System.Data.dll!System.Data.SqlClient.SqlDataReader.TryReadInternal(bool setTimeout, out bool more) Unknown
    System.Data.dll!System.Data.SqlClient.SqlDataReader.ReadAsync.AnonymousMethod__0(System.Threading.Tasks.Task t) Unknown
    System.Data.dll!System.Data.SqlClient.SqlDataReader.InvokeRetryable<bool>(System.Func<System.Threading.Tasks.Task, System.Threading.Tasks.Task<bool>> moreFunc, System.Threading.Tasks.TaskCompletionSource<bool> source, System.IDisposable objectToDispose)   Unknown
    System.Data.dll!System.Data.SqlClient.SqlDataReader.ReadAsync(System.Threading.CancellationToken cancellationToken) Unknown
    System.Data.dll!System.Data.Common.DbDataReader.ReadAsync() Unknown
>   SqlDataReaderReadAsync.exe!SqlDataReaderReadAsyncProgram.Form_Shown(object sender, System.EventArgs e) Line 36  C#
    [Resuming Async Method] 

(aparado ainda mais por questões de concisão).

O todoReadSyncOverAsync as coisas me parecem particularmente suspeitas. É como se o SqlClient estivesse assumindo que uma leitura síncrona não seria bloqueada, como se não soubesse usar IO sem bloqueio ou algo assim. No entanto, ao visualizar a fonte de referência ou descompilar com o JustDecompile, parece que deve haver suporte assíncrono, mas, de alguma forma, heuristicamente / de forma alternativa, decidiu não usá-lo.

Então, como obtenho o *Async() coisas no SqlClient para realmente serem assíncronas? Eu pensei que esses métodos deveriam permitir que eu escrevesse programas GUI responsivos sem threads, sem precisar usarTask.Run() porque embrulhar coisas síncronas emTask.Run() apenas torná-los assíncronos é inútil ...?

Estou usando .net-4.7.02542.

Estou assumindo que este é um erro .net e envieiconectar # 3139210 (EDIT: conectar está morto, eu tenho um projeto de reprodução emhttps://github.com/binki/connect3139210)

ATUALIZAR: A Microsoft reconhece o erro e o corrigirá em .net-4.7.3.Usei um caso de "Suporte técnico" de uma assinatura do VS para relatar o erro e obter essas informações.

questionAnswers(0)

yourAnswerToTheQuestion