我的MySQL连接抛出了空引用,尽管这段代码在一年前运行良好
调试器指示异常的行包含
" connection = new MySqlConnection(connectionString);":
DBConnect MySqlConnection = new DBConnect();
string[] resultArray = MySqlConnection.GetValidUser(
"tbl_user",
tbEmail.Text,
tbPassword.Text
);
//THROWS null reference exception in method 'private bool OpenConnection()'
//A first chance exception of type 'System.ArgumentException' occurred in System.Data.dll
这是我的DBConnect类:
class DBConnect
{
private MySqlConnection connection;
private string server;
private string database;
private string uid;
private string password;
public DBConnect()
{
server = "x.x.x.x";
database = "...";
uid = "...";
password = "...";
string connectionString = "SERVER=" + server + ";" +
"DATABASE=" + database + ";" +
"UID=" + uid + ";" +
"PASSWORD=" + password + ";";
connection = new MySqlConnection(connectionString);
}
private bool OpenConnection()
{
try
{
connection.Open();
return true;
}
catch (MySqlException ex)
{
switch (ex.Number)
{
case 0:
MessageBox.Show("Cannot connect to MySQL server.");
break;
case 1045:
MessageBox.Show("Invalid username or password.");
break;
}
return false;
}
}
public string[] GetValidUser(string dbTable, string dbUsername, string dbPassword)
{
string query = "SELECT id,email,password FROM " + dbTable +
" WHERE email='" + dbUsername +
"' AND password='" + dbPassword + "'";
string[] resultArray = new string[3];
if (this.OpenConnection() == true)
{
MySqlCommand cmd = new MySqlCommand(query, connection);
MySqlDataReader dataReader = cmd.ExecuteReader();
while (dataReader.Read())
{
resultArray[0] = dataReader.GetInt32(0).ToString();
resultArray[1] = dataReader.GetString(1);
resultArray[2] = dataReader.GetString(2);
}
dataReader.Close();
this.CloseConnection();
}
return resultArray;
}
}
可以找到数据库类的原始代码here。
答案 0 :(得分:9)
这不是NullReferenceException
的答案 - 我们仍然在评论中解决这个问题;这是安全部分的反馈。
我们首先要看的是SQL注入;这很容易解决 - 见下文(注意我也整理了其他一些东西)
// note: return could be "bool" or some kind of strongly-typed User object
// but I'm not going to change that here
public string[] GetValidUser(string dbUsername, string dbPassword)
{
// no need for the table to be a parameter; the other two should
// be treated as SQL parameters
string query = @"
SELECT id,email,password FROM tbl_user
WHERE email=@email AND password=@password";
string[] resultArray = new string[3];
// note: it isn't clear what you expect to happen if the connection
// doesn't open...
if (this.OpenConnection())
{
try // try+finally ensures that we always close what we open
{
using(MySqlCommand cmd = new MySqlCommand(query, connection))
{
cmd.Parameters.AddWithValue("email", dbUserName);
// I'll talk about this one later...
cmd.Parameters.AddWithValue("password", dbPassword);
using(MySqlDataReader dataReader = cmd.ExecuteReader())
{
if (dataReader.Read()) // no need for "while"
// since only 1 row expected
{
// it would be nice to replace this with some kind of User
// object with named properties to return, but...
resultArray[0] = dataReader.GetInt32(0).ToString();
resultArray[1] = dataReader.GetString(1);
resultArray[2] = dataReader.GetString(2);
if(dataReader.Read())
{ // that smells of trouble!
throw new InvalidOperationException(
"Unexpected duplicate user record!");
}
}
}
}
}
finally
{
this.CloseConnection();
}
}
return resultArray;
}
现在,您可能会想到"代码太多" - 当然;和工具有助于此!例如,假设我们做了:
public class User {
public int Id {get;set;}
public string Email {get;set;}
public string Password {get;set;} // I'll talk about this later
}
然后我们可以使用dapper和LINQ为我们完成所有繁重的工作:
public User GetValidUser(string email, string password) {
return connection.Query<User>(@"
SELECT id,email,password FROM tbl_user
WHERE email=@email AND password=@password",
new {email, password} // the parameters - names are implicit
).SingleOrDefault();
}
这可以你拥有的所有(包括安全地打开和关闭连接),但它干净安全地完成。如果it方法返回null
的{{1}}值,则表示未找到匹配项。如果返回非null User
实例 - 它应该包含仅使用基于名称的约定的所有预期值(意思是:属性名称和列名称匹配)。
您可能会注意到,唯一剩下的代码是实际上有用的代码 - 它并不是无聊的管道。像dapper 这样的工具是你的朋友;使用它们。
最后;密码。你永远不应该存储密码。永远。从来没有。甚至没有加密。决不。您应仅存储哈希密码。这意味着您永远无法检索它们。相反,您应该对用户提供的内容进行哈希处理,并将其与预先存在的哈希值进行比较;如果哈希匹配:这是一个通行证。这是一个复杂的领域,需要进行重大更改,但应该执行此操作。这个很重要。你目前所拥有的是不安全的。
答案 1 :(得分:2)
除其他外,听起来你的连接字符串有问题 - 来自评论:
while&#34; connection = new MySqlConnection(); connection.ConnectionString = connectionString;&#34;抛出异常语句&#34; connection = new MySqlConnection();&#34;没有......
这里的区别很简单:在后者中你没有设置连接字符串 - 所以听起来你的连接字符串没有正确地转义值(很可能是密码) ;你可以尝试:
var cs = new DbConnectionStringBuilder();
cs["SERVER"] = server;
cs["DATABASE"] = database;
cs["UID"] = uid;
cs["PASSWORD"] = password;
var connectionString = cs.ConnectionString;