Xamarin MysqlConnector 奇怪的 NullReferenceException 错误
Xamarin MysqlConnector weird NullReferenceException error
我想为学校项目制作一个小而简单的移动应用程序,我知道从 phone 连接到数据库出于安全原因并不好,但基本上只有我会碰它。
为了将我的 Xamarin 应用程序连接到 Mysql,我下载了扩展程序 MysqlConnector (https://www.nuget.org/packages/MySqlConnector/2.1.8?_src=template)
起初似乎一切正常,但现在我认为他们的库中存在与 Xamarin 不兼容的问题:
我似乎总是在第 2 行的第二个查询中遇到空引用异常
reader = cmd.ExecuteReader();.我不知道为什么,没有什么是空的,我已经打印了所有内容。
(我在它发生的地方发表了评论)我严重怀疑这是他们图书馆的问题,因为他们总共有 3720 万次下载。但也许这只是一个兼容性冲突,但这让第一个查询工作变得奇怪。
这是我当前的所有代码:
using PuppyChinoBestelling.Views;
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
using MySqlConnector;
using System.Threading.Tasks;
namespace PuppyChinoBestelling.ViewModels
{
public class LoginViewModel : BaseViewModel
{
public Command LoginCommand { get; }
public string Mail { get; set; }
public string Pass { get; set; }
public LoginViewModel()
{
Pass = string.Empty;
Mail = string.Empty;
LoginCommand = new Command(OnLoginClicked);
}
private async void OnLoginClicked(object obj)
{
MySqlConnection conn = new MySqlConnection("private");
try
{
conn.Open();
Console.WriteLine("Conn opened!");
}
catch(Exception ex)
{
Console.WriteLine("Error " + ex.Message);
}
string sql = @"SELECT * FROM users WHERE email = @email;";
var cmd = conn.CreateCommand();
cmd.CommandText = sql;
cmd.Parameters.AddWithValue("@email", Mail);
var reader = cmd.ExecuteReader();
if (reader.HasRows)
{
sql = @"SELECT * FROM users WHERE email = @email;";
cmd = conn.CreateCommand();
cmd.Parameters.Clear();
cmd.CommandText = sql;
cmd.Parameters.AddWithValue("@email", Mail);
reader = cmd.ExecuteReader(); //null reference happening here idk why
string pwdHashed = reader.GetString(5);
bool validPwd = BCrypt.Net.BCrypt.Verify(Pass, pwdHashed);
conn.Close();
if (validPwd)
{
await Shell.Current.GoToAsync($"//{nameof(AboutPage)}");
}
else
{
Console.WriteLine("Foute logingegevens!");
}
}
else
{
Console.WriteLine("Je bestaat niet!");
}
}
}
}
提前致谢!
很难确定,但问题很可能是因为您没有关闭 reader 和命令,并且您不能在同一个连接上有多个命令。
此外,您需要使用 reader.Read
推进 reader。
在任何情况下都不需要首先 运行 命令两次。您已经掌握了第一个 运行.
的所有信息
- 您还需要使用
using
处理所有内容。这会自动关闭连接。
- 不要
SELECT *
,只 select 您需要的列。
- 理想情况下,您会计算给定密码的哈希值,并将其发送到数据库服务器进行检查,而不是从数据库中提取真正的密码哈希值(可能存在安全风险)。
- 不要将散列存储为字符串。而是将它们存储为具有
varbinary
数据类型的二进制文件,并在 C# 端转换为 byte[]
。
- 不清楚为什么你只处理打开连接的错误,而不处理执行命令的错误。
private async void OnLoginClicked(object obj)
{
const string sql = @"
SELECT Pass
FROM users
WHERE email = @email;
";
using (var conn = new MySqlConnection("private"))
using (var cmd = new MySqlCommand(sql, conn))
{
try
{
conn.Open();
Console.WriteLine("Conn opened!");
}
catch(Exception ex)
{
Console.WriteLine("Error " + ex.Message);
return; // no point continuing
}
cmd.Parameters.AddWithValue("@email", Mail);
using (var reader = cmd.ExecuteReader())
{
if (!reader.Read())
{
Console.WriteLine("Je bestaat niet!");
return; // no point continuing
}
string pwdHashed = (string)reader["Pass"];
conn.Close();
bool validPwd = BCrypt.Net.BCrypt.Verify(Pass, pwdHashed);
if (validPwd)
{
await Shell.Current.GoToAsync($"//{nameof(AboutPage)}");
}
else
{
Console.WriteLine("Foute logingegevens!");
}
}
}
}
另一种方法是完全删除 reader 并使用 ExecuteScalar
private async void OnLoginClicked(object obj)
{
const string sql = @"
SELECT Pass
FROM users
WHERE email = @email;
";
using (var conn = new MySqlConnection("private"))
using (var cmd = new MySqlCommand(sql, conn))
{
try
{
conn.Open();
Console.WriteLine("Conn opened!");
}
catch(Exception ex)
{
Console.WriteLine("Error " + ex.Message);
return; // no point continuing
}
cmd.Parameters.AddWithValue("@email", Mail);
string pwdHashed = cmd.ExecuteScalar() as string;
conn.Close();
if (pwdHashed is null)
{
Console.WriteLine("Je bestaat niet!");
return; // no point continuing
}
bool validPwd = BCrypt.Net.BCrypt.Verify(Pass, pwdHashed);
if (validPwd)
{
await Shell.Current.GoToAsync($"//{nameof(AboutPage)}");
}
else
{
Console.WriteLine("Foute logingegevens!");
}
}
}
我想为学校项目制作一个小而简单的移动应用程序,我知道从 phone 连接到数据库出于安全原因并不好,但基本上只有我会碰它。
为了将我的 Xamarin 应用程序连接到 Mysql,我下载了扩展程序 MysqlConnector (https://www.nuget.org/packages/MySqlConnector/2.1.8?_src=template)
起初似乎一切正常,但现在我认为他们的库中存在与 Xamarin 不兼容的问题:
我似乎总是在第 2 行的第二个查询中遇到空引用异常 reader = cmd.ExecuteReader();.我不知道为什么,没有什么是空的,我已经打印了所有内容。 (我在它发生的地方发表了评论)我严重怀疑这是他们图书馆的问题,因为他们总共有 3720 万次下载。但也许这只是一个兼容性冲突,但这让第一个查询工作变得奇怪。
这是我当前的所有代码:
using PuppyChinoBestelling.Views;
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
using MySqlConnector;
using System.Threading.Tasks;
namespace PuppyChinoBestelling.ViewModels
{
public class LoginViewModel : BaseViewModel
{
public Command LoginCommand { get; }
public string Mail { get; set; }
public string Pass { get; set; }
public LoginViewModel()
{
Pass = string.Empty;
Mail = string.Empty;
LoginCommand = new Command(OnLoginClicked);
}
private async void OnLoginClicked(object obj)
{
MySqlConnection conn = new MySqlConnection("private");
try
{
conn.Open();
Console.WriteLine("Conn opened!");
}
catch(Exception ex)
{
Console.WriteLine("Error " + ex.Message);
}
string sql = @"SELECT * FROM users WHERE email = @email;";
var cmd = conn.CreateCommand();
cmd.CommandText = sql;
cmd.Parameters.AddWithValue("@email", Mail);
var reader = cmd.ExecuteReader();
if (reader.HasRows)
{
sql = @"SELECT * FROM users WHERE email = @email;";
cmd = conn.CreateCommand();
cmd.Parameters.Clear();
cmd.CommandText = sql;
cmd.Parameters.AddWithValue("@email", Mail);
reader = cmd.ExecuteReader(); //null reference happening here idk why
string pwdHashed = reader.GetString(5);
bool validPwd = BCrypt.Net.BCrypt.Verify(Pass, pwdHashed);
conn.Close();
if (validPwd)
{
await Shell.Current.GoToAsync($"//{nameof(AboutPage)}");
}
else
{
Console.WriteLine("Foute logingegevens!");
}
}
else
{
Console.WriteLine("Je bestaat niet!");
}
}
}
}
提前致谢!
很难确定,但问题很可能是因为您没有关闭 reader 和命令,并且您不能在同一个连接上有多个命令。
此外,您需要使用 reader.Read
推进 reader。
在任何情况下都不需要首先 运行 命令两次。您已经掌握了第一个 运行.
的所有信息- 您还需要使用
using
处理所有内容。这会自动关闭连接。 - 不要
SELECT *
,只 select 您需要的列。 - 理想情况下,您会计算给定密码的哈希值,并将其发送到数据库服务器进行检查,而不是从数据库中提取真正的密码哈希值(可能存在安全风险)。
- 不要将散列存储为字符串。而是将它们存储为具有
varbinary
数据类型的二进制文件,并在 C# 端转换为byte[]
。 - 不清楚为什么你只处理打开连接的错误,而不处理执行命令的错误。
private async void OnLoginClicked(object obj) { const string sql = @" SELECT Pass FROM users WHERE email = @email; "; using (var conn = new MySqlConnection("private")) using (var cmd = new MySqlCommand(sql, conn)) { try { conn.Open(); Console.WriteLine("Conn opened!"); } catch(Exception ex) { Console.WriteLine("Error " + ex.Message); return; // no point continuing } cmd.Parameters.AddWithValue("@email", Mail); using (var reader = cmd.ExecuteReader()) { if (!reader.Read()) { Console.WriteLine("Je bestaat niet!"); return; // no point continuing } string pwdHashed = (string)reader["Pass"]; conn.Close(); bool validPwd = BCrypt.Net.BCrypt.Verify(Pass, pwdHashed); if (validPwd) { await Shell.Current.GoToAsync($"//{nameof(AboutPage)}"); } else { Console.WriteLine("Foute logingegevens!"); } } } }
另一种方法是完全删除 reader 并使用 ExecuteScalar
private async void OnLoginClicked(object obj)
{
const string sql = @"
SELECT Pass
FROM users
WHERE email = @email;
";
using (var conn = new MySqlConnection("private"))
using (var cmd = new MySqlCommand(sql, conn))
{
try
{
conn.Open();
Console.WriteLine("Conn opened!");
}
catch(Exception ex)
{
Console.WriteLine("Error " + ex.Message);
return; // no point continuing
}
cmd.Parameters.AddWithValue("@email", Mail);
string pwdHashed = cmd.ExecuteScalar() as string;
conn.Close();
if (pwdHashed is null)
{
Console.WriteLine("Je bestaat niet!");
return; // no point continuing
}
bool validPwd = BCrypt.Net.BCrypt.Verify(Pass, pwdHashed);
if (validPwd)
{
await Shell.Current.GoToAsync($"//{nameof(AboutPage)}");
}
else
{
Console.WriteLine("Foute logingegevens!");
}
}
}