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

Posted

技术标签:

【中文标题】如何捕获从 SQL Server 到 C# 应用程序的消息选项卡的所有内容?【英文标题】:How to capture everything from Message Tab from SQL Server to C# Application? 【发布时间】:2019-08-16 04:04:44 【问题描述】:

我的应用程序的一点点背景。

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

Restored Database 有一个存储过程,它调用 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 问题的所有内容,它是 derivatives。

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

希望我的问题很清楚。

【问题讨论】:

【参考方案1】:

早安,

注意!此消息未标记为“社区 wiki”,因此它是由特定人员以其名义撰写的,这不是共享文章。如果您有 cmets,请使用 cmets 而不是更改 OP 打算提供的内容(例如内容中的额外学习点)。谢谢!

在下面的脚本中,我给出一个处理嵌套存储过程错误的例子。基本思想是使用TRY/CATCH来防止引发错误并停止事务,并使用OUTPUT将错误信息返回给上层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

【讨论】:

抱歉@RonenAriely,我忘了说,我只能更改我的 C# 应用程序而不是存储过程。 嗨,如果 SP 不包含处理错误的过程,则错误不会在嵌套 SP 的级别中“向上移动”到客户端应用程序(C#)。在这种情况下你不能展示不存在的东西。如果您不处理嵌套 SP,则不会显示任何错误。您应该联系控制 SP 代码的人,并 (1) 检查是否有处理错误的程序 - 在这种情况下,我们需要查看 SP 的代码,或者 (2) 要求他尽自己的一份力量并编辑根据要求编码。 顺便说一句,在这种情况下,您应该从问题中删除标签“tsql”,因为现在您提供了新信息,表明它与“tsql”无关,因为您无法控制SP 的“tsql”......这成为一个纯 C# 问题,但答案与我之前的评论“你不能呈现不存在的东西”相同:-) 在所有 SP 中,我在每次交易后都有 PRINT 语句。我希望能捕捉到所有这些,因为它会出现在消息中。我还提供了要从 SQL Server 捕获到我的 C# 应用程序的所需消息的屏幕截图。 感谢您的意见。抱歉,一开始我把你弄糊涂了。

以上是关于如何捕获从 SQL Server 到 C# 应用程序的消息选项卡的所有内容?的主要内容,如果未能解决你的问题,请参考以下文章

如何从 C# 代码将 SQL Server CE 迁移到 SQL Server 2012 Express

如何从 C# 动态运行 SQL Server CE [Windows mobile] 中的 SQL 脚本文件?

如何使用 C# 从 SQL Server 数据库中逐行将数据检索到 datagridview 中

如何使用 json 从 sql server ASP.net 中检索数据

过程中的 Raiserror (SQL Server 2014) 无法捕获客户端 (c#)

如何从 c# 将 SQL Server 数据库转换/导出到 MSAccess