Ado.net Fill方法在运行不存在的存储过程时不会抛出错误

Mik*_*ike 3 .net c# sql ado.net

我正在使用企业库和ADO的原始Fill方法的组合.这是因为我需要自己打开和关闭命令连接,因为我捕获事件信息消息

到目前为止,这是我的代码

        // Set Up Command 
        SqlDatabase db = new SqlDatabase(ConfigurationManager.ConnectionStrings[ConnectionName].ConnectionString);
        SqlCommand command = db.GetStoredProcCommand(StoredProcName) as SqlCommand;
        command.Connection = db.CreateConnection() as SqlConnection;

        // Set Up Events for Logging
        command.StatementCompleted += new StatementCompletedEventHandler(command_StatementCompleted);
        command.Connection.FireInfoMessageEventOnUserErrors = true;
        command.Connection.InfoMessage += new SqlInfoMessageEventHandler(Connection_InfoMessage);

        // Add Parameters
        foreach (Parameter parameter in Parameters)
        {
            db.AddInParameter(command, 
                parameter.Name, 
                (System.Data.DbType)Enum.Parse(typeof(System.Data.DbType), parameter.Type), 
                parameter.Value);
        }

            // Use the Old Style fill to keep the connection Open througout the population
            // and manage the Statement Complete and InfoMessage events
            SqlDataAdapter da = new SqlDataAdapter(command);
            DataSet ds = new DataSet();

            // Open Connection
            command.Connection.Open();

            // Populate
            da.Fill(ds);

            // Dispose of the adapter
            if (da != null)
            {
                da.Dispose();
            }

            // If you do not explicitly close the connection here, it will leak!  
            if (command.Connection.State == ConnectionState.Open)
            {
                command.Connection.Close();
            }
Run Code Online (Sandbox Code Playgroud)

...

现在,如果我传入变量StoredProcName ="ThisProcDoesNotExists"

并运行这个代码.CreateCommand也不是da.Fill通过错误消息.为什么是这样.我可以告诉它没有运行的唯一方法是它返回一个包含0个表的数据集.但是在调查错误时,并不表示该程序不存在.

编辑进一步调查command.Connection.FireInfoMessageEventOnUserErrors = true; 导致错误被压缩到InfoMessage事件中

来自BOL

将FireInfoMessageEventOnUserErrors设置为true时,先前作为异常处理的错误现在将作为InfoMessage事件处理.所有事件立即触发并由事件处理程序处理.如果FireInfoMessageEventOnUserErrors设置为false,则在过程结束时处理InfoMessage事件.

我想要的是来自Sql的每个print语句来创建一个新的日志记录.将此属性设置为false会将其组合为一个大字符串.因此,如果我将属性设置为true,那么问题是我可以从错误中识别出打印消息

另一个编辑

所以现在我有了代码,以便将标志设置为true并检查方法中的错误号

    void Connection_InfoMessage(object sender, SqlInfoMessageEventArgs e)
    {
        // These are not really errors unless the Number >0
        // if Number = 0 that is a print message
        foreach (SqlError sql in e.Errors)
        {
            if (sql.Number == 0)
            {
                Logger.WriteInfo("Sql Message",sql.Message);
            }
            else
            {

                // Whatever this was it was an error 
                throw new DataException(String.Format("Message={0},Line={1},Number={2},State{3}", sql.Message, sql.LineNumber, sql.Number, sql.State));
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

现在的问题是,当我抛出错误时,它不会冒泡到发出调用的语句,甚至是上面的错误处理程序.它只是轰炸了那条线

人口看起来像

            // Populate
            try
            {
                da.Fill(ds);
            }
            catch (Exception e)
            {
                throw new Exception(e.Message, e);
            }
Run Code Online (Sandbox Code Playgroud)

现在即使我看到调用代码和方法仍然在调用堆栈中,这个异常似乎没有冒出来?

Car*_*lin 5

我花了一些时间在这上面得出结论,InfoMessageHandler不会在执行命令对象的范围内引发.因此,您在事件中抛出的异常不会冒泡到命令对象的方法.它必须在不同的线程中执行.

我假设您使用的是Visual Studio 2008,因为我能够在该环境中完全重现您的问题.当我将代码迁移到Visual Studio 2010时,仍然使用框架3.5,新的IDE捕获了自定义异常,但我无法找到一种简单的方法来捕获代码中的异常.Visual Studio 2010调试器在调试多个线程方面要好得多.

如果要捕获此事件的异常,则必须编写可以跟踪线程异常的代码.