简体   繁体   中英

SqlCommand.ExecuteReaderAsync stops firing InfoMessage event after first SELECT statement in a stored procedure

I have to use stored procedures for accessing data and also consume messages (like PRINT 'hello' ) sent from the DB engine.

When I a use InfoMessage event of SQL connection and fill the data into DataTable , everything works perfect.

However, when I have to read data sequentially and use SqlDataReader.ExecuteReaderAsync , connection stops firing InfoMessage after first select statement in the stored procedure:

C# code:

using (SqlConnection con = new SqlConnection("connection-string"))
{
    con.Open();
    con.InfoMessage += (s, e) => {
        Console.WriteLine(e.Message);
    };

    using (SqlCommand command = new SqlCommand("spTestMessage", con))
    {
        command.CommandType = System.Data.CommandType.StoredProcedure;

        SqlDataReader reader = await command.ExecuteReaderAsync();

        int cntr = 0;

        while (reader.Read())
        {
            Console.WriteLine($"Loaded row {cntr++}");
        }

        // reader.NextResult(); // this line forces firing rest of InfoMessage events
    }
}

SQL Stored Procedure:

CREATE PROCEDURE [dbo].[spTestMessage]
AS

PRINT 'Before select 1'
select * from MyTable
PRINT 'After select 1'

PRINT 'Before select 2'
select * from MyTable
PRINT 'After select 2'

Program output:

Before select 1

Why it stops working? I thing there is something wrong with Reader, because when I use command.ExecuteNonQueryAsync(); instead of command.ExecuteReaderAsync(); , it also works.

I incidentally found out, that commented row reader.NextResult(); forces the connection to flush the messages and fire remaining events. However, its a very unlucky workaround.

Thanks for any help!

The reason why your command.ExecuteNonQueryAsync() stops giving your result after the first run, with or without reader.ReadAsync() , because any async SQL command will be completed as soon as the first result is returned to the client, and info messages does count as a result. And when you fire the reader.NextResult() or await reader.NextResultAsync() it checks with the reader for further results.

If you want to read more about Asynchronous SQL processing you can check Remus answer and for NextResult check out this example .

Consuming the InfoMessages :

var _msgs = new List<string>();
using (System.Data.SqlClient.SqlConnection con = new System.Data.SqlClient.SqlConnection(<YourConnectionString>))
{
    //Appending an event handler for InfoMessages
    con.InfoMessage += delegate (object sender, SqlInfoMessageEventArgs args)
    {
        //reader will invoke the delegate on every itteration of results coming from query
        _msgs.Add(args.Message);
        return;
    };
    using (var cmd = new System.Data.SqlClient.SqlCommand("spTestMessage", con))
    {
        cmd.CommandType = CommandType.StoredProcedure;
        con.Open();
        using (System.Data.SqlClient.SqlDataReader reader = await cmd.ExecuteReaderAsync())
        {
            var incr = 0;
            while (await reader.ReadAsync())
            {
                //Statements to read data from Table1
                Console.WriteLine(reader.GetString(0));
                incr++;
            }
            while (await reader.NextResultAsync())
            {
                while (await reader.ReadAsync())
                {
                     //Statements to read data from Table2
                     Console.WriteLine(reader.GetString(0));
                     incr++;
                 }
             }
         }
     } 
}

Note: The above procedure can be used with Synchronous operations as well just change the signature of the methods from async to sync.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM