MySQL连接抛出null引用

时间:2015-03-25 09:32:41

标签: c# mysql connection

我的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

2 个答案:

答案 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;