How do I handle NullReferenceException with my code - vb.net

How do I handle this type of error or exception?
Try
If log.Trim = txtUSN.Text Then
MessageBox.Show("USN found: " & log)
Else
MessageBox.Show("USN not found: " & log)
End If
Catch ex as Exception
MessageBox.Show(ex.Message)
The message was "Object reference not set to an instance of an object."
This is the rest of the code:
Dim log As String
Dim sql As New SqlCommand
sql.Connection = MyConnection
sql.CommandText = "SELECT * FROM dbo.tblAcc WHERE USN = '" & txtUSN.Text & "' "
MyConnection.Open()
log = sql.ExecuteScalar
MyConnection.Close()

The simple answer is your trying to use an object that is nothing. If it's nothing you can't use it, hence "Object reference not set to an instance of an object."
As already mentioned in my comments above, the culprit is: log. I'm not sure where you have declared this or when your using it and how your using it, for all I know it's nothing. If you have more code that would be greatly appreciated as I can point out where it's nothing, until then here's how to get around your issue.
Try
If log IsNot Nothing Then
If log.Trim = txtUSN.Text Then
MessageBox.Show("USN found: " & log)
Else
MessageBox.Show("USN not found: " & log)
End If
Else
MessageBox.Show("Log is NOTHING!")
End If
Catch ex as Exception
MessageBox.Show(ex.Message)
End Try
**EDIT**
After you posted more code in a comment (please post code in the area, not in comment's) it seem's there are a few issue's. You have log defined as a string; when you do this set it to something like: String.Empty instead of nothing. Also you want to sse the ExecuteScalar method to retrieve a single value (for example, an aggregate value) from a database which could be an integer, long, single etc data types. In your query your selecting everything, you can't call ExecuteScalar to return that data... I would recommend looking up information about building queries and executing them, it's to long for me to get in depth with it here.
Happy Coding!

Make sure that (log) is not an empty string.
if not String.IsNullorEmpty(log) then
end if

Related

BluetoothLEDevice.FromIdAsync Returns Uncastable __ComObject

Before we even start: In researching this problem I've looked at dozens of posts here and elsewhere, and realize that VB is the worst for Bluetooth programming. However, this is for a client who has a massive legacy VB system and I have no choice.
According to MS documentation, the BluetoothLEDevice.FromIdAsync is supposed to return a BluetoothLEDevice object but on my system it returns a generic System.__ComObject that I can't cast to a BluetoothLEDevice. I have tried Cast and DirectCast but neither work. The sample C++ code I've looked at doesn't require any type of casting; the variable is declared and set using the BluetoothLEDevice.FromIdAsync function without any dramas.
Here is my test code.
Private Sub ConnectToDevice(di As DeviceInformation)
'
' di.id = "BluetoothLE#BluetoothLE48:5f:99:3c:fd:36-84:2e:14:26:9e:7b"
'
Debug.Print("Connecting To " & di.Name & " at " & Now.ToShortTimeString)
Dim genericObject As Object
Dim myDevice As BluetoothLEDevice
Try
genericObject = BluetoothLEDevice.FromIdAsync(di.Id)
Catch ex As Exception
Debug.Print(ex.Message)
End Try
If Not IsNothing(genericObject) Then Debug.Print("Using 'Object' yeilds " & genericObject.ToString)
Try
myDevice = BluetoothLEDevice.FromIdAsync(di.Id)
Catch ex As Exception
Debug.Print(ex.Message)
End Try
End Sub
And here is the output:
Connecting To TM-2021090161 at 2:08 PM
Using 'Object' yeilds System.__ComObject
Exception thrown: 'System.InvalidCastException' in testBTLE.exe
Unable to cast object of type 'System.__ComObject' to type 'Windows.Devices.Bluetooth.BluetoothLEDevice'.
And a screen shot of the returned genericObject:
The FromIdAsync needs to be run async which I couldn't do because I got an error stating it didn't have an awaiter. It turns out that I needed to NuGet the System.Runtime.Windowsruntime dll. I added the Await and it's working now.
Thanks to Andrew for pointing me in the right direction.

Strange bug in MSHTML Assembly

Dim u As UInteger = 0
Try
Do
u += 1
j = DirectCast(o.item(d), HTMLTableRow).cells
Loop
Catch ex As Exception
MsgBox("Access No." & u & " throws:" & ex.GetType.ToString & ":" & ex.Message)
End Try
This is the piece of code I used as a test - a dead loop, infinitely accessing the variable O (assigned in code before) and assigning it to the variable J with some operation (O and J are both MSHTML.IHTMLElementCollection type). Under the debug mode, I can run it normally until the counter u reaches its upper limit. However, under the release mode, after loop for 5000~6000 times (in each test the number is different) it will throw "NullReferenceException". Note that I've just accessed O, never changed it, why is the exception? Is this a bug of MSHTML the assembly? Moreover, if I make a minor change:
Dim u As UInteger = 0, v As Object
Try
Do
u += 1
v = DirectCast(o.item(d), HTMLTableRow)
Loop
Catch ex As Exception
MsgBox("Access No." & u & "throws:" & ex.GetType.ToString & ":" & ex.Message)
End Try
That is, to remove the ".cells", and then there will be no exceptions. What's going on here? (This cannot be used as a workaround because in my program the ".cells" must be accessed)
If I use TryCatch block to ignore the exception and just try again, it won't run normally any more - throwing the exception for each loop. There must be some qualitative changes.
OK, MSHTML, you win. I have to use the dumbest workaround. Just try...catch the exception and try again. After numerous tests, I got the following possible exceptions that must be handled:
COMException, when you can simply try the statement throwing this again.
UnauthorizedAccessException, when you can simply try again like the last one.
NullReferenceException, when you CANNOT simply try again as you'll again catch the same exception. You'll have to initialize a new HTMLDocument and reload the URL, then do the remaining work.
Wanting anyone with a more elegant solution. I swear I'll never use the hideous Assembly if possible.

How to continue insert if one row fails

I have a while loop where it fetches record from csv and inserts to sql table. Now csv may contain many rows.
What I want is if one row fails just log to a file and continue with next record. I was thinking of try and catch but that will exit the program. So, any suggestions?
while (csv.readnextline)
'assign csv columns to objects
try
'insert to db
Catch ex As Exception
'write to log file
End Try
I need the above code to continue after catching an exception.
Thanks
Try and catch do not exit the program, they just control the flow of the code in case something exceptional happens.
When an exception happens in the try block, the execution continues on the first line of the (corresponding) catch block. After the execution of the catch block, the code continues on the first line after the catch, which in your case could be the End While which will continue the loop.
So an construction like this
While dr.Read
Try
InsertRowIntoDataBase()
Catch ex As Exception
LogErrorToFile(ex)
End Try
End While
should work for you.
However, this is a bad design, as it will generate and log an exception, no matter what the problem is, whether the data is invalid, or the sql server is down, or even if there is an error in your code (e.g. some lurking NullReferenceException). You should limit the handling of exception to a specific case, e.g. to a problem with the database, like this:
While dr.Read
Try
InsertRowIntoDataBase()
Catch ex As SqlClient.SqlException
LogDataBaseErrorToFile(ex)
End Try
End While
Also, if there are known possible problems with the data (e.g. a string in the csv where an integer is expected) it's better to just check that than to use an exception mechanism, something along these lines:
While dr.Read
Try
If Not IsRowValid() Then
LogInvalidDataToFile()
Continue While
End If
InsertRowIntoDataBase()
Catch ex As SqlClient.SqlException
LogDataBaseErrorToFile()
Catch ex As Exception
LogGenericErrorToFile()
End Try
End While
no it won't exit the program, depending on how/where you handle the exception. If you do something like :
Dim WrongValuedLinesList As New List(Of String)
Dim ConversionFailedList As New List(Of String)
Dim InsertionFailedList As New List(Of String)
Dim NumberOfInsertedLines As integer = 0
For Each (CurrentLine in my csv)
' 1. line processing
Try
' (process my line : split, convert, check range...)
If (I know the insertion will fail) Then
' (Store information about that wrong line, in List, log, or do nothing)
WrongValuedLinesList.Add(" This line : " & CurrentLine
& " has wrong values because...
Continue For
End If
Catch ex as exception
' (here handle the line conversion failed : store in list, or log, or do nothing ...)
' for expl :
ConversionFailedList.Add(" Conversion failed for line " & CurrentLine
& " exception details : " & ex.message " )
End Try
' 2. Line insertion
Try
'(insert my processed data into database)
NumberOfInsertedLines +=1
Catch ex as exception
' (here handle the insertion failed exception (expl : primary key might not be unique)
' : store in list, log, do nothing...)
' for example :
InsertionFailedList.Add(" Insertion failed for line " & CurrentLine
& " exception details : " & ex.message " )
End Try
Next
(Here you might wanna report how things went to your user using
your error list.)

Error that can't be fixed?

I'm getting an error in my VB.NET application that connects to my SQL database. It connects fine, but for some reason I can't fix this error. When I try to fix it, it moves from one part of my script to another part of my script (both of which were working yesterday). The error details are:
Unfortunately, it's difficult for me to describe how I produced this result, because it has happened in multiple parts of my code, and the only thing that these parts have in common is their interaction with Listbox1.
The first part of code to get this error was:
Dim sqlpage As MySqlCommand = New MySqlCommand("SELECT * FROM [" & frmMain.ListBox1.SelectedItem.value & "]", con)
Then I got the same exact error for:
Private Sub ListBox1_SelectedValueChanged( _
ByVal sender As Object, ByVal e As System.EventArgs) _
Handles ListBox1.SelectedValueChanged
Try
Form1.Label1.Text = ListBox1.SelectedItem
Form1.Show()
Catch myerror As MySqlException
MessageBox.Show("Error Setting Up Project Page: " & myerror.Message)
End Try
End Sub
More specifically:
Form1.Label1.Text = ListBox1.SelectedItem
And then I got it a few more times, but I think the examples above will suffice.
Since there are no "With Block Variables" in the examples above then the only other option is that it's object related. I've tried different methods of defining and redefining the object variables related to the error. However, the results are the same.
In response to Juxtaposition's answer, my original problem has been solved however two new problems have come up specifically because I turned Option Strict on.
The first is:
Error1: Option Strict On disallows late binding.
The code in question is:
Try
' Retrieving the projects list.
con.Open()
DataAdapter2.SelectCommand = sqlprojects
DataAdapter2.Fill(ds2, "projects")
ListBox1.Items.Clear()
For Each DataRow In ds2.Tables("projects").Rows
' Error occurs on the line below
ListBox1.Items.Add(DataRow("project_name"))
Next
con.Close()
Catch myerror As MySqlException
MessageBox.Show("Error Retrieving Projects List: " & myerror.Message)
End Try
The second is:
Error 2: Option Strict On disallows implicit conversions from 'Object' to 'String'.
The code in question is:
Private Sub ListBox1_SelectedValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles ListBox1.SelectedValueChanged
Try
If ListBox1.SelectedItem IsNot Nothing Then
' Error occurs on the line below
Form1.Label1.Text = ListBox1.SelectedItem
End If
Form1.Show()
Catch myerror As MySqlException
MessageBox.Show("Error Setting Up Project Page: " & myerror.Message)
End Try
End Sub
It worked out... so I thank all of you for your time and patience.
You should always (99.999999% of the time) write VB.NET code with Option Strict On, unless you are writing interop code or interfacing with an esoteric database provider.
Simply place the words "Option Strict On" at the top of your file.
This will allow you to catch errors like the one you are dealing with.
Without Option Strict On you are allowed to write code like you have written:
Form1.Label1.Text = ListBox1.SelectedItem
The issue with that code is that is implicity tries to convert an object (ListBox1.SelectedItem) to a string (Form1.Label1.Text).
Turn option strict on and the compiler will give you an error up front.
You will then be forced to rewrite your code as such:
If ListBox1.SelectItem IsNot Nothing then
Form1.Label1.Text = ListBox1.SelectedItem
End If
Focus on this line for the moment:
Form1.Label1.Text = ListBox1.SelectedItem
If you're getting a NullReferenceException on this line, then one of the following has to be true:
Form1 is null
Form1.Label1 is null
ListBox1 is null
You can try to determine this by adding lines like these just before the above line:
Console.Writeline("Form1: " & (Form1 Is Nothing))
Console.Writeline("Form1.Label1: " & (Form1.Label1 Is Nothing))
Console.Writeline("ListBox1:" & (ListBox1 Is Nothing))
You should see a line that outputs true; that's the first clue. But then the next question is, why is it null? From what you've shown so far, I can't say.
Make sure ListBox1.SelectedItem is not Nothing in both of those circumstances.
Your original errors can be fixed without having to use Option Explicit On. You need to ensure that the Listbox.SelectedItem has a value before using it. The code should be written as:
If frmMain.ListBox1.SelectedItem IsNot Nothing Then
Dim sqlpage As MySqlCommand = New MySqlCommand("SELECT * FROM [" & frmMain.ListBox1.SelectedItem.value & "]", con)
End If
and
Try
If ListBox1.SelectedItem IsNot Nothing Then
Form1.Label1.Text = ListBox1.SelectedItem
End If
Form1.Show()
Catch myerror As MySqlException
MessageBox.Show("Error Setting Up Project Page: " & myerror.Message)
End Try
Update #2
Your second error should be fixed by changing the code to:
If ListBox1.SelectedItem IsNot Nothing Then
Form1.Label1.Text = ListBox1.SelectedItem.ToString
End If
Option Explicit On means that you have to explicitly convert data types.

Building A True Error Handler

I am trying to build an error handler for my desktop application. The code Is in the class ZipCM.ErrorManager listed below.
What I am finding is that the outputted file is not giving me the correct info for the StackTrace.
Here is how I am trying to use it:
Try
'... Some stuff here!
Catch ex As Exception
Dim objErr As New ZipCM.ErrorManager
objErr.Except = ex
objErr.Stack = New System.Diagnostics.StackTrace(True)
objErr.Location = "Form: SelectSite (btn_SelectSite_Click)"
objErr.ParseError()
objErr = Nothing
End Try
Here is the class:
Imports System.IO
Namespace ZipCM
Public Class ErrorManager
Public Except As Exception
Public Location As String
Public Stack As System.Diagnostics.StackTrace
Public Sub ParseError()
Dim objFile As New StreamWriter(Common.BasePath & "error_" & FormatDateTime(DateTime.Today, DateFormat.ShortDate).ToString().Replace("\", "").Replace("/", "") & ".log", True)
With objFile
.WriteLine("-------------------------------------------------")
.WriteLine("-------------------------------------------------")
.WriteLine("An Error Occured At: " & DateTime.Now)
.WriteLine("-------------------------------------------------")
.WriteLine("LOCATION:")
.WriteLine(Location)
.WriteLine("-------------------------------------------------")
.WriteLine("FILENAME:")
.WriteLine(Stack.GetFrame(0).GetFileName())
.WriteLine("-------------------------------------------------")
.WriteLine("LINE NUMBER:")
.WriteLine(Stack.GetFrame(0).GetFileLineNumber())
.WriteLine("-------------------------------------------------")
.WriteLine("SOURCE:")
.WriteLine(Except.Source)
.WriteLine("-------------------------------------------------")
.WriteLine("MESSAGE:")
.WriteLine(Except.Message)
.WriteLine("-------------------------------------------------")
.WriteLine("DATA:")
.WriteLine(Except.Data.ToString())
End With
objFile.Close()
objFile = Nothing
End Sub
End Class
End Namespace
What is happenning is the .GetFileLineNumber() is getting the line number from objErr.Stack = New System.Diagnostics.StackTrace(True) inside my Try..Catch block. In fact, it's the exact line number that is on.
Any thoughts of what is going on here, and how I can catch the real line number the error is occuring on?
Edit: Changed the code to account for the Exception.StackTrace being a string rather than a real StackTrace
You're creating a new StackTrace, so then it will be for the line you're declaring it on, if you want the line number of the original exception, use the stack trace in Exception.StackTrace.
I think you're being a little confused, I can't see why you create the new StackTrace at all?
Edit: Added more bits to the answer here since easier to see the syntax than in a comment
Currently you have the line
objErr.Stack = New System.Diagnostics.StackTrace(True)
Which means that you're creating a whole new stacktrace, starting when you're creating it.
Instead change that line to:
objErr.Stack = New System.Diagnostics.StackTrace(ex, True)
Which will have the stacktrace from when the error actually happened.
Edit: Added complete sample:
Private Sub a1()
Try
a2()
Catch ex As Exception
Dim st As New StackTrace(True)
Debug.WriteLine(String.Format("ST after exception, will give line number for where st was created. Line No: {0}", st.GetFrame(0).GetFileLineNumber()))
st = New StackTrace(ex, True)
Debug.WriteLine(String.Format("ST after exception using exception info, will give line number for where exception was created. Line No: {0}", st.GetFrame(0).GetFileLineNumber()))
End Try
End Sub
Private Sub a2()
Dim st As New StackTrace(True)
Debug.WriteLine(String.Format("ST before exception, will give line number for where st was created. Line No: {0}", st.GetFrame(0).GetFileLineNumber()))
Dim b As Integer = 0
Dim a As Integer = 1 / b
End Sub
SOLVED: You should change the wrong instruction, of the original code:
.WriteLine(Stack.GetFrame(0).GetFileLineNumber())
with this new one:
.WriteLine(Stack.GetFrame(Stack.FrameCount - 1).GetFileLineNumber)
and you will see, it will return the exact Line_Number of code
where the run time error occurs!!
You do not need to include a Stack property for your ErrorManager, because you have access to the stack trace through the exception.
From experience, I would create a Shared Sub Write(ex As Exception, location As String) method on the ErrorManager, and call in your Catch statement as:
ZipCM.ErrorManager.Write(ex, "Form: SelectSite (btn_SelectSite_Click)")
This change results in cleaner code, reduces the need to write lots of code in each Catch statement, and allows you to change the implementation of Write without having to revisit/rework/refactor each Catch statement.
For instance, you can change the Write method to also call Debug.WriteLine(ex) so you can see which exceptions you are handling during debugging without having to open the file. Moreover, you may want to include WriteNotify method that displays a message box of the exception then calls the Write method to log the exception.