我如何在c#的消息框中显示错误消息,SQL异常(唯一标识符)在3层应用程序中
本文关键字:消息 唯一 异常 标识符 应用程序 3层 SQL 显示 错误 | 更新日期: 2023-09-27 18:04:14
我正在使用c#和SQL设计一个windows窗体三层应用程序。我设计了用户注册页面,该页面使用存储过程与数据库连接。我已经把文本框从用户输入。我对用户名列使用了唯一约束。因为我使用3层应用程序架构,所以我已经把我的register_user函数在BLL和调用它从按钮在UI。当我在文本框中输入重复的用户名时,它会抛出一个异常(如预期的那样)的唯一约束,但我希望的是,这条消息应该显示在一个窗口框中,我的应用程序不应该停止工作。我试过在register_user函数中使用try catch,但它没有用。同样,我也尝试在我的UI(注册按钮)中使用try catch,但再次失败。我在这里张贴我的代码:由于
//BLL public void register_user(string First_Name,string Last_Name,string User_Name,string Password,string Date_Of_Birth,string Security_Question,string Security_Answer)
{
try
{
DAL obj = new DAL();
obj.OpenConnection();
obj.LoadSpParameters("UR", First_Name, Last_Name, User_Name, Password, Date_Of_Birth, Security_Question, Security_Answer);
obj.ExecuteQuery();
obj.UnLoadSpParameters();
}
catch (SqlException ex)
{
MessageBox.Show(ex.ToString());
}
finally
{
DAL obj2 = new DAL();
obj2.CloseConnection();
}
}
UI //
private void register_button_Click(object sender, EventArgs e)
{
if (first_name_text.Text == "" || last_name_text.Text == "" || user_name_text.Text == "" || password_text.Text == "" || confirm_password_text.Text == "" || answer_txt.Text == "")
{
alert1_label.Show();
error1_label.Show();
error1_label.Text = "You cannot left mandatory fields empty";
}
if (password_text.Text.Length <= 8)
{
alert1_label.Show();
error1_label.Show();
error1_label.Text = "Password must be greater than 8 characters";
password_text.Clear();
confirm_password_text.Clear();
return;
}
if (first_name_text.Text.Any(Char.IsDigit) || first_name_text.Text.Any(Char.IsPunctuation) || first_name_text.Text.Any(Char.IsSeparator) || first_name_text.Text.Any(Char.IsSymbol))
{
alert1_label.Show();
error1_label.Show();
error1_label.Text = "Numbers and Special Characters are not allowed in first name";
first_name_text.Clear();
return;
}
if (last_name_text.Text.Any(Char.IsDigit) || last_name_text.Text.Any(Char.IsPunctuation) || last_name_text.Text.Any(Char.IsSeparator) || last_name_text.Text.Any(Char.IsSymbol))
{
alert1_label.Show();
error1_label.Show();
error1_label.Text = "Numbers and Special Characters are not allowed in last name";
last_name_text.Clear();
return;
}
if (!user_name_text.Text.Any(Char.IsLetter))
{
alert1_label.Show();
error1_label.Show();
error1_label.Text = "User Name must contain atleast one alphabet, and must be atleast 4 characters long.";
user_name_text.Clear();
return;
}
if (user_name_text.Text.Length <= 3)
{
alert1_label.Show();
error1_label.Show();
error1_label.Text = "User Name must contain atleast one alphabet, and must be atleast 4 characters long.";
user_name_text.Clear();
return;
}
else
{
try
{
error1_label.Hide();
alert1_label.Hide();
BLL obj = new BLL();
obj.register_user(first_name_text.Text, last_name_text.Text, user_name_text.Text, password_text.Text, date_of_birth_text.Text, security_question_text.SelectedItem.ToString(), answer_txt.Text);
MessageBox.Show("Registration Successful");
UP frm = new UP();
frm.Text = "Welcome" + " " + first_name_text.Text;
this.Dispose();
frm.Show();
}
catch(SqlException ex)
{
MessageBox.Show(ex.Message);
}
}
}
您的BLL中的一个问题是关闭未打开的连接。在你的register_user
方法中,你有一个finally块,它创建了一个new DAL()
对象,然后你调用CloseConnection
。
没有看到这个实现,我怀疑您想要关闭在try块中创建的DAL对象。如果是这种情况,一种可能的修复方法是将obj变量提升到try块之外,以便它在try和finally块中可用。
请记住,变量在c#中有块作用域。
public void register_user(string First_Name,string Last_Name,string User_Name,string Password,string Date_Of_Birth,string Security_Question,string Security_Answer)
{
DAL obj = null; // initialize to a value
try
{
obj = new DAL();
obj.OpenConnection();
obj.LoadSpParameters("UR", First_Name, Last_Name, User_Name, Password, Date_Of_Birth, Security_Question, Security_Answer);
obj.ExecuteQuery();
obj.UnLoadSpParameters();
}
catch (SqlException ex)
{
MessageBox.Show(ex.ToString());
}
finally
{
if (obj!=null) // check for null in case the constructor did throw an exception
{
obj = new DAL();
obj.CloseConnection();
}
else
{
Debug.Assert(obj!=null, "DAL not intialized");
}
}
}
超出了这个答案的范围,您必须重新考虑捕获异常的原因和时间。作为一般规则,只有知道如何处理异常,才能捕获异常。在当前的代码示例中,BLL和UI层都处理异常。如果操作得当,BLl层不应该有向用户显示错误的责任。它应该把错误传递给调用者,在这种情况下,UI层和调用者可以决定做什么。
如果您在上述示例中采纳了该建议,则应该删除MessageBox.Show
,并可能由日志记录和/或错误收集代替。
改变你的catch:
catch (SqlException ex)
{
MessageBox.Show(ex.ToString());
}
:
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
这样可以捕获try块中的任何错误,而不仅仅是"SqlException"类型的错误。您当前的错误可能不是"SqlException"
您的错误可能是因为UI无法从代码中访问。
让数据层生成UI组件违反了n层的设计原则。在n层中,您希望在设计的早期就决定在哪个层处理异常以及如何传输消息,因为修改可能很困难。
常见的方案:
- 所有异常都被冒泡到UI层,在那里它们被适当地处理。数据层或业务层中唯一捕获的是可以在该层中正确处理的错误,或者捕获、记录和重新抛出。 具有自定义返回类型,允许从业务层返回消息。这可以是来自所有BL方法的成功布尔返回值和某种类型的全局错误存储库("发生了一个或多个错误,这里是错误日志"类型的消息传递),也可以是包含异常的结果类型或复杂结果对象,可能还包括有关事务状态的其他信息等。
像"catch (SqlException ex)"那样捕获特定的异常是很好的做法,但为了调试,请尝试将"catch (SqlException ex)"替换为下面的语句。
catch (Exception exception)
{
System.Diagnostics.Debug.WriteLine(exception.Message);
throw;
}
在客户端和业务层都这样做,然后放置一个断点,调试,看看会发生什么。
我的猜测是在第一个catch语句中发生了一些事情,产生了另一种类型的异常,而这种异常没有在客户机上捕获。