英文:
ExecuteReader? Connection property has not been initialized
问题
我正在尝试创建一个登录表单,但当我尝试登录时,我收到一个异常。
我正在使用一个名为 conexaoDB.cs
的单独文件来创建与数据库相关的连接信息。
在按钮外部:
ConexaoDB conexao = new ConexaoDB();
在按钮内部:
try
{
conexao.conn();
string sql = "SELECT * FROM users WHERE users_login = @login AND users_pass = @senha";
SqlCommand command = new SqlCommand(sql);
command.Parameters.AddWithValue("@login", login);
command.Parameters.AddWithValue("@senha", senha);
SqlDataReader reader = command.ExecuteReader();
if (reader.HasRows)
{
MessageBox.Show("弹出下一个窗口 = " + login + " // " + senha);
tryLogin = true;
}
else
{
MessageBox.Show("登录或密码无效。");
tryLogin = false;
}
}
catch (Exception ex)
{
MessageBox.Show("捕获异常: " + ex.Message);
}
这仅用于学习SQL连接,不是一个真实的具有真实登录名和密码的数据库。
英文:
I'm trying to do a login form, but when i try to login, I get an exception.
I'm using a separate file called conexaoDB.cs
to create the connection with all info about the DB
Outside the button:
ConexaoDB conexao = new ConexaoDB();
Inside the button:
try
{
conexao.conn();
string sql = "SELECT * FROM users WHERE users_login = @login AND users_pass = @senha";
SqlCommand command = new SqlCommand(sql);
command.Parameters.AddWithValue("@login", login);
command.Parameters.AddWithValue("@senha", senha);
SqlDataReader reader = command.ExecuteReader();
if (reader.HasRows)
{
MessageBox.Show("Popup next window = " + login + " // " + senha);
tryLogin = true;
}
else
{
MessageBox.Show("Login ou senha inválidos.");
tryLogin = false;
}
}
catch (Exception ex)
{
MessageBox.Show("Catch: " + ex.Message);
}
This is only to learn SQL connection, is not a real database with real logins and passwords
答案1
得分: 0
不要使用ConexaoDB相关的内容,尤其是如果你尝试保持一个连接一直处于打开状态。这是不好的实践,内置的连接池将工作得更好。
以下代码应该可以工作:
try
{
string sql = "SELECT * FROM users WHERE users_login = @login AND users_pass = @senha";
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
using (var command = new SqlCommand(sql, connection))
{
command.Parameters.AddWithValue("@login", login);
command.Parameters.AddWithValue("@senha", senha);
using (var reader = command.ExecuteReader())
{
tryLogin = reader.HasRows;
if (tryLogin)
{
// 在消息框中显示密码是极其不良的实践,但我假设这是为了测试
MessageBox.Show("弹出下一个窗口 = " + login + " // " + senha);
}
else
{
MessageBox.Show("登录或密码无效。");
}
}
}
}
}
catch (SqlException ex) // 不要捕获过于宽泛的异常,要具体指明
{
MessageBox.Show("捕获: " + ex.Message);
}
using
语句会负责关闭和处理资源释放,而 SqlConnection
会返回连接池,以便重复使用。
重要:
不应该将密码以明文形式存储在数据库中。最佳实践是生成一个带有盐的哈希值,并将哈希值存储在数据库中。在验证用户时,你需要再次计算用户输入的密码的哈希值,然后比较这两个哈希值。这可以确保如果密码表被盗,对攻击者来说是无用的。
英文:
Drop the ConexaoDB stuff, especially if you are trying to keep one connection open at all time. That is bad practice, built-in connection pooling will work much better.
This should work:
try
{
string sql = "SELECT * FROM users WHERE users_login = @login AND users_pass = @senha";
using (var connection = new SqlConnection(connectionString)
{
connection.Open();
using (var command = new SqlCommand(sql, connection)
{
command.Parameters.AddWithValue("@login", login);
command.Parameters.AddWithValue("@senha", senha);
using (var reader = command.ExecuteReader())
{
tryLogin = reader.HasRows;
if (tryLogin)
{
// Extremely bad practice to show password in a messagebox, but I assume it's for test
MessageBox.Show("Popup next window = " + login + " // " + senha);
}
else
{
MessageBox.Show("Login ou senha inválidos.");
}
}
}
}
}
catch (SqlException ex) // Don't catch too broad an exception, be specific
{
MessageBox.Show("Catch: " + ex.Message);
}
The usings are taking care of closing and disposing and the SqlConnection goes back to the connection pool and will be reused.
Important:
You should not store passwords as clear text in the database. Best practice is to generate a hash, with a salt and store the hashed value in the database. When authenticating the user you compute the hash again on the password input by the user and compare the two hashes. This assures that your password table is useless to an attacker if it gets stolen.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论