当与 SQL 服务器的连接失败时,如何确定准确的异常 (C#)?

How can I determine the precise exception when a connection to SQL Server fails (C#)?

我有一个 (Windows Forms) 应用程序,它将安装在不同用户的桌面上;它将允许他们根据连接到 SQL 服务器数据库并从某些表中读取记录的自定义代码生成报告。

连接字符串是:

Data Source=PLATYPUS;Initial Catalog=Duckbills;Persist Security Info=True;User ID=lilabner;Password=d0GpAtCh42;Connect Timeout=120

我理解这意味着如果以下所有条件都为真:

The user's machine has the SQL Server client software installed
The SQL Server client has been configured to access the PLATYPUS database
The table "Duckbills" exists in that database
The username and password are what is expected

...那么连接就成功了

如果以上任何一项都等同于错误,我想向用户显示一条 "user-friendly" 消息,以通俗易懂的方式告知他们问题是什么以及如何解决。我如何测试这些不同的问题,以便在连接失败时向用户显示最合适的消息。

这是相关的现有代码:

DataSet dsUsage = new DataSet();
SqlConnection conn =
    new SqlConnection("SERVER=PLATYPUS;DATABASE=Duckbills;UID=lilabner;PWD=d0GpAtCh42;Connection Timeout=0");
SqlDataAdapter da = new SqlDataAdapter();
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = "Exec sp_ViewPlatypi";
da.SelectCommand = cmd;
conn.Open();
da.Fill(dsUsage);
conn.Close();

DataTable dtUsage = dsUsage.Tables[0];
if (dtUsage.Rows.Count > 0)
{
    foreach (DataRow productUsageByMonthDataRow in dtUsage.Rows)
    {
        . . .

catch (Exception ex)
{
    String exDetail = String.Format(PlatypusConstsAndUtils.ExceptionFormatString, ex.Message, Environment.NewLine, ex.Source, ex.StackTrace);
    MessageBox.Show(exDetail);
}

如您所见,我有一个 "catch all"(无双关语意)Catch 块。我想要这样的东西:

catch (SQLServerException sex)
{
    MessageBox.Show("SQL Server not available - go tell the DBA");
}
catch (NoTableException ntex)
{
    MessageBox.Show("Go tell the DBA there's no such table");
}
catch (BadPwdException sex)
{
    MessageBox.Show("Your username and/or password are bad - go tell it to the Marines");
}
catch (Exception ex)
{
    String exDetail = String.Format(PlatypusConstsAndUtils.ExceptionFormatString, ex.Message, Environment.NewLine, ex.Source, ex.StackTrace);
    MessageBox.Show(exDetail);
}

...但我不知道,首先,如果有的话,是否有可能通过连接异常消息获得这种粒度,其次 - 如果是 - 相应的异常类型是什么。

剥离您的代码以处理异常 (catch (Exception ex))。然后,在您的 catch 块中放置一个断点。将调试器附加到您的代码,当它遇到 catch 块时,将 ex 变量拖到您的手表中 window。在那里,您将看到异常的所有详细信息,并且可以确定您需要什么才能更好地处理出现的各种异常。

根据 MethodMan 的建议和 TheShaman 的 link,我将该代码改编为:

catch (SqlException sex)
{
    for (int i = 0; i < sex.Errors.Count; i++)
    {
        String sexDetail = String.Format("SQL Exception #{0}{1}Source: {2}{1}Number: {3}{1}State: {4}{1}Class: {5}{1}Server: {6}{1}Message: {7}{1}Procedure: {8}{1}LineNumber: {9}",
            i+1, // Users would get the fantods if they saw #0 
            Environment.NewLine, 
            sex.Errors[i].Source, 
            sex.Errors[i].Number, 
            sex.Errors[i].State, 
            sex.Errors[i].Class, 
            sex.Errors[i].Server, 
            sex.Errors[i].Message, 
            sex.Errors[i].Procedure, 
            sex.Errors[i].LineNumber);
        MessageBox.Show(sexDetail);
    }
}
catch (Exception ex)
{
    String exDetail = String.Format(UsageRptConstsAndUtils.ExceptionFormatString, ex.Message, Environment.NewLine, ex.Source, ex.StackTrace);
    MessageBox.Show(exDetail);
}

举个例子: