Testing if object Is Nothing results in 'Object required' error - asp-classic

I am supporting some classic ASP pages, one of which uses and re-uses an object conn and disposes of it either when the .asp page finishes processing or right before the page redirects to another page.
<%
dim conn
...
set conn = server.CreateObject("adodb.connection")
...
sub cleanUp()
conn.Close
set conn = nothing
end sub
...
sub pageRedirect(url)
call cleanUp()
response.Redirect url : response.End
end sub
...
' very end of file
call cleanUp()%>
I've found that if there is a redirect, I get a server error right at the line conn.Close, Microsoft VBScript runtime error '800a01a8' Object required. I figure there's no reason why that line would execute more than once but to be safe I rewrote the function
sub cleanUp()
if(not (conn Is Nothing)) then
conn.Close
set conn = Nothing
end if
end sub
But I still get that exact error, now at the line if(not (conn Is Nothing))!! I thought the purpose of Is Nothing was to do a test before using the variable name conn precisely to prevent that 'object required' error, but the test is throwing the same error.
What other test can I use to make sure conn isn't referenced if it'd already been set to Nothing?

is nothing is used to test for an object reference, if the variable does not contain such then the test is invalid & raises an error, so conn can only be tested after its been set to something.
You can;
if isobject(conn) then
if not (conn Is Nothing) then set conn = nothing
end if

Use option explicit (each time a script runs without option explicit, a puppie dies out there), you probably would have detected the problem earlier as Nilpo mentioned.
When you dim a variable that you are going to use as an object reference and test it on Nothing, make it a habbit to set it to Nothing at initialization time(*): dim myObject : Set myObject = Nothing.
(*) Not really at initialization, because the dim's are handled before a routine starts, but when you put all your dim's at the top of a routine, it will practically be the same.

Use the IsNothing function. You should also check that it is an object.
sub cleanUp()
if Not IsNothing(conn) then
if IsObject(conn) then
conn.Close
end if
set conn = nothing
end if
end sub
That being said, I would do it like this since setting a variable to nothing does no harm.
sub cleanUp()
if IsObject(conn) then
conn.Close
end if
set conn = nothing
end sub
More importantly though, your problem is that conn is not in scope for your subroutine. You should probably pass it in as a parameter.

Related

Classic ASP test if Server can create object

With this code:
Dim xmlDOM
Set xmlDOM = Server.CreateObject("MSXML2.DOMDocument.3.0")
How can I test that the CreateObject function has been successful?
If it didn't work you might get an error. Otherwise, you could use the following code:
Dim xmlDOM
'dont fail on error'
On Error Resume Next
Set xmlDOM = Server.CreateObject("MSXML2.DOMDocument.3.0")
On Error GoTo 0 'turn error handling off again'
If Not xmlDOM Is Nothing Then
'not null: it worked'
Else
'xmlDOM is nothing. It was not able to create the object. '
'Check create permissions in COM+'
End If

Try/Catch Failing Incorrectly

I'm trying to use Try/Catch to handle a potential failed connection to a database. There's a Response.Redirect command in the Catch section. Whenever the page loads it redirects as per the Catch section whether the code in the Try section fails or not.
If I comment out the Response.Redirect command in the Catch section the page loads just fine. Similarly, if I replace the Response.Redirect command with code to populate a control on the page with the supposed error being trapped the Try section succeeds. It's something about having Response.Redirect in the Catch section...
Private Sub Page_Load(Sender As Object, e As eventargs) Handles Me.Load
Try
Dim sqlcon As New System.Data.SqlClient.SqlConnection(ConfigurationManager.ConnectionStrings("SarcoidsConnectionString").ConnectionString)
Dim cmd As New System.Data.SqlClient.SqlCommand("SELECT PortalEnabled FROM [tlkSettings]", sqlcon)
sqlcon.Open()
Dim dbReader As System.Data.SqlClient.SqlDataReader = cmd.ExecuteReader()
If dbReader.HasRows Then
While dbReader.Read()
If dbReader("PortalEnabled") = True Then
Response.Redirect("~/SubmitWizard.aspx")
Else
Response.Redirect("~/Maintenance.aspx")
End If
End While
End If
sqlcon.Close()
Catch ex As Exception 'Display Maintenance page if database cannot be connected to
Response.Redirect("~/Maintenance.aspx")
End Try
End Sub
Response.Redirect() without the second parameter of False will generate a ThreadAbortException because .End() is called on the Response object, so the following lines are the issue:
If dbReader("PortalEnabled") = True Then
Response.Redirect("~/SubmitWizard.aspx")
Else
Response.Redirect("~/Maintenance.aspx")
End If
Change it to this:
If dbReader("PortalEnabled") = True Then
Response.Redirect("~/SubmitWizard.aspx", False)
Else
Response.Redirect("~/Maintenance.aspx", False)
End If
The second parameter to Redirect() is the endResponse value, when setting it to False this tells the response to not call .End() and thus does not generate a ThreadAbortException.
Per MSDN documentation:
When you use this method in a page handler to terminate a request for one page and start a new request for another page, set endResponse to false and then call the CompleteRequest method. If you specify true for the endResponse parameter, this method calls the End method for the original request, which throws a ThreadAbortException exception when it completes. This exception has a detrimental effect on Web application performance, which is why passing false for the endResponse parameter is recommended. For more information, see the End method.
Read HttpResponse.Redirect Method documentation for more information.
I think the Problem is related to the other Response.Redirect Statements:
If dbReader("PortalEnabled") = True Then
Response.Redirect("~/SubmitWizard.aspx")
Else
Response.Redirect("~/Maintenance.aspx")
End If
Response.Redirect always throws a ThreadAbortException. This is caught in your exception handler as it catches any exception. Either you substitute the Reponse.Redirect calls or you add a handler the catches ThreadAbortExceptions:
Try
'...
Catch threadAbort As ThreadAbortException
Throw
Catch ex As Exception
'...
End Try
By the way: you should add some Using statements to close the connection and free other objects reliably.

Unable to open recordset

I have written a basic asp classic class that handles all connections to our database.
when called everything works fine the first time but the second time it is called the recordset does not open any ideas?
Class SQLConnection
Private Sub Class_Initialize
set ConnectionObject = Server.CreateObject("ADODB.Connection")
Set RecordsetObject = Server.CreateObject("ADODB.Recordset")
End Sub
Private Sub Class_Terminate
Set ConnectionObject = Nothing
Set RecordsetObject = Nothing
End Sub
Public Default Property Get Item(sString)
On Error Resume Next
Item = RecordsetObject(sString)
On Error GoTo 0
If Err.Number <> 0 then
Item = null
End if
End Property
Public Sub MoveNext
If Not RecordsetObject.EOF Then RecordsetObject.MoveNext
End Sub
Public Function EOF
EOF = RecordsetObject.EOF
End Function
Public Sub Open(SQLStr,ConnStr)
ConnectionObject.Open ConnStr
RecordsetObject.Open SQLStr, ConnectionObject, 3
End Sub
Public Sub Close
RecordsetObject.Close
ConnectionObject.Close
End Sub
End Class
Set SQLConn = New SQLConnection
SQLConn.Open "SELECT top 10 id FROM tblProfileVillages", ConnectionString
Do While Not SQLConn.EOF
Response.write(SQLConn("id"))
SQLConn.MoveNext
Loop
SQLConn.Close
Set SQLConn = nothing
I think the error is in the Item property, you will have to check the err.Number before calling on error goto 0.
Use it like this:
Public Default Property Get Item(sString)
On Error Resume Next
Item = RecordsetObject(sString)
If Err.Number <> 0 then
Item = null
End if
On Error GoTo 0
End Property
Also I haven't seen "null" in vbScript yet. Is that a constant you made, or could it be that you are missing an error somewhere?
The on error goto next business can be annoying sometimes. :)
It turns out if your sql statement can't be displayed in a grid then the object closes instantly like say an insert statement.
I solved this by checking if the object is open before running code with If RecordsetObject.State = 1 then

ASP.NET Page_Load runs twice due to Bitmap.Save

I have created an VB.NET page to record views for ads and will call page from img src.
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
Dim insert_number As Integer = 0
Dim ad_id As Integer = 0
If Request.QueryString("adid") Is Nothing Then
ad_id = 0
Else
If Not Integer.TryParse(Request.QueryString("adid"), ad_id) Then
ad_id = 0
End If
End If
Dim connectStr As String = System.Configuration.ConfigurationManager.AppSettings("connectStr").ToString()
Dim myconnection As SqlConnection = New SqlConnection(connectStr)
Dim mySqlCommand As SqlCommand
myconnection.Open()
Try
mySqlCommand = New SqlCommand("sp_record", myconnection)
mySqlCommand.CommandType = CommandType.StoredProcedure
mySqlCommand.Parameters.AddWithValue("#record_id", ad_id)
insert_number = mySqlCommand.ExecuteNonQuery()
Catch ex As Exception
End Try
myconnection.Close()
Dim oBitmap As Bitmap = New Bitmap(1, 1)
Dim oGraphic As Graphics = Graphics.FromImage(oBitmap)
oGraphic.DrawLine(New Pen(Color.Red), 0, 0, 1, 1)
'Response.Clear()
Response.ContentType = "image/gif"
oBitmap.Save(Response.OutputStream, System.Drawing.Imaging.ImageFormat.Gif)
'oBitmap.Dispose()
'oGraphic.Dispose()
End Sub
Unless I comment oBitmap.Save line, the code runs twice and it makes two inserts (store prcoedure runs twice) to Database.
I have tried AutoEventWireup = "true" and "false" at #PAGE. "true" runs code twice, "false" did not do anything (no error) and did not give any output as well.
I have also tried following version of creating 1pixel image output but it did run twice as well (it requires aspcompat=true in #PAGE part):
'Response.ContentType = "image/gif"
'Dim objStream As Object
'objStream = Server.CreateObject("ADODB.Stream")
'objStream.open()
'objStream.type = 1
'objStream.loadfromfile("c:\1pixel.gif")
'Response.BinaryWrite(objStream.read)
Any ideas are welcome.
You may want to do an onload function for the image to see why it's being called a second time. I'm guessing that it's getting loaded somewhere in the preload and then being called (.Save) during the page load as well and that's why you're seeing the double entry.
If you are trying to get unique page loads, you may want to try putting the oBitmap.Save line within a check for postback like this within the page load:
If Page.IsPostback = False Then
'Bitmap Code Here
End If
And see if that fixes it for you.
If you're loading data from a database, you'll want to make sure that it also is within that PostBack check (because a. you're loading the data twice and b. it can cause these double postbacks in some circumstances).
Edit: Wanted to edit code section to include all bitmap code, not just the save.
Not sure about the specifics, but that is a lot of code within in Page_Load function.
Generally, the way I would solve this type of problem is to have some sort of page arguments that you can check for in order to do the correct things. Either add some get/post parameters to the call that you can check for or check things like the Page.IsPostBack.
I realize this is an old post but I had an similar issue where the page was firing twice on the postback. I found several posts sugesting what is being dicusses here. However, what corrected my issue was setting the page directive property AutoEventWireup=false at the page level.
Here is a good article How to use the AutoEventWireup attribute in an ASP.NET Web Form by using Visual C# .NET that helped me solve this.
Hope this helps!
Risho

checking if row was inserted

I am trying to check whether a row is getting inserted into my database. It is throwing an error even when it does insert (it's a database issue that will get resolved later when I get a newer version of Microsoft Access), so I can't check whether the insert is successful based on whether there's an error or not. I think I need to check the AffectedRows of something, but I'm not sure what. I've been looking for info on how to do this but I can't figure out how to make it work for my exact situation. Here's a general idea of what my code looks like:
Protected Sub Wizard1_FinishButtonClick(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.WizardNavigationEventArgs) Handles Wizard1.FinishButtonClick
'code for collecting data...
'Define Connection
Dim myConn As New OleDbConnection
myConn.ConnectionString = AccessDataSource1.ConnectionString
myConn.Open()
'Insert command
Dim myIns1 As New OleDbCommand("INSERT INTO tableCourse 'long insert command here...
'Execute command and handle errors
Try
myIns1.ExecuteNonQuery()
Catch myException5 As Exception
End Try
'Close connection
myConn.Close()
-UPDATE-
I tried it like this:
'Execute command, handle errors, and check if row was inserted
Dim numInserted As Integer = 0
Try
numInserted = myIns1.ExecuteNonQuery()
Catch myException As Exception
Finally
If numInserted = 0 Then
Label1.Text = "Sorry, an error occured."
Else
Label1.Text = "Thank you! Your new course approval request has been submitted."
End If
End Try
But the numInserted is coming out as 0 every time even though the insert is successful. It may have to do with the fact that myIns1.ExecuteNonQuery() throws an error even though the insert is successful.
-EDIT- I discovered that the "duplicate values" error is because it is somehow attempting to insert the record twice. I have no idea why it's doing that though.
The ExecuteNonQuery function returns the affected number of rows...
Dim numInserted as Integer = myIns1.ExecuteNonQuery()
If numInserted = 0 Then
' no rows were inserted...throw exception?
End If
The symptoms you are describing (known no duplicates, but inserts throw duplicate errors) sound like your Access database needs Compacting and Repairing.
You should do this on a regular basis. (Always backup up first).

Resources