如何捕获从 SQL 服务器的消息选项卡到 C# 应用程序的所有内容?

How to capture everything from Message Tab from SQL Server to C# Application?

我申请的一些背景知识。

我正在使用 File Watcher windows 服务寻找 C# .bak 特定文件夹中的文件,然后使用它来恢复该文件所属的数据库。

还原的数据库有一个存储过程调用 10 个不同的存储过程。 File Watcher's 恢复完成后执行存储过程的功能。

存储过程是 [1_IMPORT_DATA_AND_PROCESS_ALL],它在自身内部调用 10 个不同的存储过程。

这是恢复完成后正在执行存储过程的方法。

// Trigger Stored Procedure after restore. 
private void triggerSP(String connectionStr)
{
    // This doesn't open the Connection. conn.Open() has to be explicitly called.
    
    SqlConnection conn = new SqlConnection(connectionStr);
    try
    {
    
    conn.Open();
    conn.FireInfoMessageEventOnUserErrors = true;
    // Capture messages returned by SQL Server.
    conn.InfoMessage += delegate (object sender, SqlInfoMessageEventArgs e)
    {
        
        message += " -> " + e.Message + " -> ";
    };
    //conn.InfoMessage += new SqlInfoMessageEventHandler(cn_InfoMessage);
    
    //.create a command object identifying the stored procedure.
    SqlCommand cmd = new SqlCommand("[dbo].[1_IMPORT_DATA_AND_PROCESS_ALL]", conn);
    cmd.CommandTimeout = 0;
    // 2. set the command object so it knows to execute a stored procedure.
    cmd.CommandType = CommandType.StoredProcedure;

    // Add a check here as well.
    // execute the command.
    SqlDataReader rdr = cmd.ExecuteReader();


    string[] info = new string[] { "Message: \n" + message };
    WriteToFile(info);

    // Since we are not using - using block we have to explicitly call Close() to close the connection.
    conn.Close();
    }
    catch (SqlException SqlEx){
    string[] error = new string[3] ;

    string msg1 = "Errors Count:" + SqlEx.Errors.Count;
    string msg2 = null;

    foreach (SqlError myError in SqlEx.Errors)
        msg2 += myError.Number + " - " + myError.Message + "/" ;

    conn.InfoMessage += delegate (object sender, SqlInfoMessageEventArgs e)
    {
        message += "\n" + e.Message;
    };

    error[0] = msg1;
    error[1] = msg2;
    error[2] = message;

    WriteToFile(error);
    }

    finally
    {
    //call this if exception occurs or not
    //in this example, dispose the WebClient
    conn.Close();
    }

}

问题

我只是从第一个存储过程(即 [1_IMPORT_DATA_AND_PROCESS_ALL] 中取回消息输出,而不是从 [1_IMPORT_DATA_AND_PROCESS_ALL] 中调用的存储过程中取回消息输出,如下所示。

一旦第一个 SP 调用另一个 SP,我的代码就会停止读取消息。

我想捕获所有正在打印的消息,如下图(下图),这是我在 SSMS 中执行 SP 时正在打印的实际消息。

这一行正在从 SP 获取消息

conn.InfoMessage += delegate (object sender, SqlInfoMessageEventArgs e)
    {
        message += " -> " + e.Message + " -> ";
    };

到目前为止,我已经提到了 this question and it's derivatives 的所有内容。

我现在无法更改存储过程,我只能更改我的 C# 应用程序。

希望我的问题很清楚。

美好的一天,

Note! This message is not marked as "community wiki" and as such it written by a specific person under his name and this is not a shared article. If you have comments then please use the comments instead of changing the content, which the OP meant to provide (for example extra learning points in the content). Thanks!

在下面的脚本中,我提供了一个处理嵌套存储过程的示例 error.The 基本思想是使用 TRY/CATCH 以防止引发错误并停止事务,并使用 OUTPUT to return 错误信息向上级SP

这只是一个基本示例...

CREATE or ALTER PROCEDURE L1 (
    @InputInt int,
    @ErrMessage NVARCHAR(MAX) OUTPUT,
    @ErrNum INT OUTPUT
)AS
    SELECT @@NESTLEVEL AS 'Inner Level'; -- this information present the level of the SP during the execution. It is not needed for the solution but for the sake of the learning and understanding of nested SP
    Select 'Start L1'

    BEGIN TRY  
        -- When the ionput is 0 we Generate a divide-by-zero error.  
        SELECT 1/@InputInt;  
    END TRY  
    BEGIN CATCH
        SET @ErrMessage = ERROR_MESSAGE()
        SELECT @ErrMessage
    END CATCH;

    SET @ErrNum = @@ERROR
    IF (@ErrNum > 0) Begin
       SELECT 'L1 error Number: ' + CONVERT(NVARCHAR(10), @ErrNum)
       Return
    END
    ELSE
       select 'L1 OK'
GO

CREATE or ALTER PROCEDURE L2 (
    @InputInt int
) AS   
    Declare @ErrMessage NVARCHAR(MAX) = '', @ErrNum INT = 0
    SELECT @@NESTLEVEL AS 'Outer Level';
    BEGIN TRY
        EXEC L1 @InputInt, @ErrMessage, @ErrNum;
    END TRY
    BEGIN CATCH
        SELECT 'There was error!'
        select @@ERROR
    END CATCH
GO

EXECUTE L2 1 -- OK
GO

EXECUTE L2 0; --Raise error in the nested stored procedures 
GO