-1

On my application, I set up a MySQL connector and login system which queries a database on my local machine, and a NullReferenceException is thrown pointing at MySQLDataReader.Close() within the Try method. The CheckCredentials function worked (almost) perfectly up until the point where I recreated the function and cleaned the code in its own module.

I did some debugging and it turns out that the exception is caused by:

If IsAlphanumeric(Username) = False Or IsAlphanumeric(Password) = False Then
    ThrowException.InvalidCredentials()
    Return False '<------ Right here!
End If

Which ultimately calls everything under Finally, before MySQLDataReader is initialized. But I don't think this should be the issue, as by calling MySQLDataReader.Close(), MySQLDataReader is already defined as MySqlDataReader.

Definitions

Private Function IsAlphanumeric(Str As String) As Boolean
    Return Regex.Match(Str.Trim(), "^[a-zA-Z0-9]*$").Success()
End Function

Private _
    MySQLConnection As MySqlConnection,
    MySQLQuery As MySqlCommand,
    MySQLDataReader As MySqlDataReader

Private ReadOnly _
    MySQLServer As String = "localhost",
    MySQLSchema As String = "gauntlet",
    MySQLTable As String = "accounts",
    MySQLUsername As String = "root",
    MySQLPassword As String = "root",
    MySQLConnectionTimeout As Integer = 20

Code

Public Function CheckCredentials(Username As String, Password As String) As Boolean
    Try
        ' Checks whether 'Username' and 'Password' are not alphanumeric and kills the operation.
        ' Helps prevent SQL injection.
        If IsAlphanumeric(Username) = False Or IsAlphanumeric(Password) Then
            ThrowException.InvalidCredentials()
            Return False
        End If

        ' MySQL connection string containing the required information in order to establish a connection to the database. 
        MySQLConnection = New MySqlConnection("Data Source=" & MySQLServer & ";" & _
                                            "Database=" & MySQLSchema & ";" & _
                                            "User ID=" & MySQLUsername & ";" & _
                                            "Password=" & MySQLPassword & ";" & _
                                            "Connection Timeout=" & MySQLConnectionTimeout.ToString)

        ' MySQL query to select all rows within columns of 'MySQLTable' with parameters username as 'Username' and password as 'Password'.
        MySQLQuery = New MySqlCommand("SELECT * FROM " & MySQLTable & " WHERE username='" & Username & "' AND password='" & Password & "'", MySQLConnection)

        ' Establishes a connection between client computer and the database.
        MySQLConnection.Open()

        ' Executes the previously defined MySQL query and reads the returned columns.
        MySQLDataReader = MySQLQuery.ExecuteReader

        ' To execute whilst 'MySQLDataReader' is open for reading the returned results from 'MySQLQuery'.
        While MySQLDataReader.Read

            ' Checks whether or not column 'admin' is set to 0 (False).
            If MySQLDataReader.GetString(4) = "0" Then
                ThrowException.PrivilegesNotMet()
                Return False
            End If

            ' Checks whether or not column 'banned' is set to 1 (True).
            If MySQLDataReader.GetString(5) = "1" Then
                ThrowException.AccountBanned(MySQLDataReader.GetString(6))
                Return False
            End If

            ' Checks whether or not strings 'Username' and 'Password' are valid matches to the returned rows' columns.
            If Username = MySQLDataReader.GetString(1) And Password = MySQLDataReader.GetString(2) Then
                Username = MySQLDataReader.GetString(1) ' Sets string 'Username' to the username as set in the table for the current account.
                Password = MySQLDataReader.GetString(2) ' Sets string 'Password' to the password as set in the table for the current account.
                Return True
            Else
                Username = Nothing ' Sets string 'Username' to nothing.
                Password = Nothing ' Sets string 'Password' to nothing.
                ThrowException.InvalidCredentials()
                Return False
            End If
        End While
    Catch ex As Exception
        ThrowException.Database()
    Finally
        If MySQLDataReader.IsClosed = False Then
            '======== NullReferenceException ======='
            MySQLDataReader.Close() : End If ' Closes the data reader.
            '======================================='

        If MySQLConnection.State = System.Data.ConnectionState.Open = True Then
            MySQLConnection.Close() : End If ' Closes the connection between the client and the database.
    End Try
    Return False
End Function
  • Duplicate of [What is a NullReferenceException and how do I fix it?](http://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it) – Bjørn-Roger Kringsjå Feb 15 '15 at 07:27

1 Answers1

0

You don't assign the reader until after the exception is thrown. As such it is never assigned. Therefore calling Close or attempting to access it properties throws the NullReferenceException.

This finally block is assuming an instance of SqlDataReader but it is in fact null.

 Finally
        If MySQLDataReader.IsClosed = False Then '== << it would actually be this line throwing the exception if my answer is correct.
            '======== NullReferenceException ======='
            MySQLDataReader.Close() : End If ' Closes the data reader.
            '======================================='

        If MySQLConnection.State = System.Data.ConnectionState.Open = True Then
            MySQLConnection.Close() : End If ' Closes the connection between the client and the database.
    End Try

So you need a null check:

Finally
    If Not MySQLDataReader Is Nothing Then
        If MySQLDataReader.IsClosed = False Then 
            MySQLDataReader.Close() : End If ' Closes the data reader.

        If MySQLConnection.State = System.Data.ConnectionState.Open = True Then
            MySQLConnection.Close() : End If 
    End If
 End Try
rism
  • 11,932
  • 16
  • 76
  • 116