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!");
             }
         }
     }