Can't set Response object in ASP Classic - asp-classic

This line:
set Response = nothing
Fails with the error
"Microsoft VBScript runtime error '800a01b6'
Object doesn't support this property or method: 'Response' "
Now, I can think of any number of reasons why the engine might not want to let me do such a seemingly silly thing, but I'm not sure how a missing method could be stopping me.
EDIT: Here is an example of what I'd like to do with this.
class ResponseBufferEphemeron
private real_response_
private buffer_
private sub class_initialize
set real_response_ = Response
end sub
private sub class_terminate
set Response = real_response_
end sub
public function init (buf)
set buffer_ = buf
set init = me
end function
public function write (str)
buffer_.add str
end function
end class
function output_to (buf)
set output_to = (new ResponseBufferEphemeron).init(buf)
end function
dim buf: set buf = Str("Block output: ") ' My string class '
with output_to(buf)
Response.Write "Hello, World!"
end with
Response.Write buf ' => Block output: Hello, World! '

You can't set the Response to nothing.
The ASP Response object is used to send output to the user from the server.
What are you trying to do? If you're trying to end the Response to the user, use
Response.End

Well, I found the answer here: http://blogs.msdn.com/b/ericlippert/archive/2003/10/20/53248.aspx
So we special-cased VBScript so that it detects when it is compiling code that contains a call to Response.Write and there is a named item in the global namespace called Response that implements IResponse::Write. We generate an efficient early-bound call for this situation only.

Related

Get result from chilkatHttp.PostUrlEncodedAsync in VB6

I am using chilkat Http.PostUrlEncodedAsync to send some data to a server and get a JSON response. When the Http_TaskCompleted Event is fired, the task.ResultType returns "object" but there is no task.GetResultObject.
The reply is received correctly (it is present in httpSessionLog.txt) but how do I get it ?
After a different search I have found it:
Private Sub Http_TaskCompleted(ByVal task As Chilkat_v9_5_0.IChilkatTask)
Dim response As New ChilkatHttpResponse
Dim success As Long
success = response.LoadTaskResult(task)
If (success <> 1) Then
Debug.Print response.LastErrorText
Exit Sub
End If
Debug.Print response.BodyStr 'this is the response string
End Sub

Write to a log file asynchronously from asp.net task

Using VB.Net (Framework version 4.5.1)
I have a program that sets up a list of (System.Threading.Tasks.Task) tasks that are executed as follows (only relevant code is shown):
po = New System.Threading.Tasks.ParallelOptions()
po.MaxDegreeOfParallelism = 5
Parallel.ForEach( task_list, po, AddressOf do_work )
The program works fine, but I want to add a log file rather than using just Console.WriteLine()
In the do_work() Sub, I want to write to a log file, for example:
Sub do_work( param As String )
Dim thread_id as String = "Thread ID " & System.Threading.Thread.CurrentThread.ManagedThreadId.ToString() & ": "
joblog_append( thread_id & "Beg" )
joblog_append( thread_id & "param = " & param )
joblog_append( thread_id & "End" )
End Sub
Ideally, I would like to create three functions such as:
joblog_open() to open a log file at the start o the program.
joblog_append() to append to the log file; callable from within any task
joblog_close() to close the log file
What is the correct way to implement such logging when the joblog_append() will be called from multiple tasks being executed on separate threads?
All attempts I have tried so far seem to be hit and miss; sometimes the data is written to the output file, sometimes it is not.
Any advice (or better yet, a code example) would be most appreciated.
Thanks in advance.
I think that the issue you have is due to the fact multiple threads are accessing the file at the same time.
A better approach would be to make sure only one thread access the file at a time. You could use a lock (see this SO) or append the messages to be written to a concurrentQueue of string, then process that queue on another thread.
The joblog_append calls _Logger.Log, which in turns enqueue the message and start a new thread to process the queue.
private _Logger as new Logger
Private Sub joblog_append(Message As String)
_Logger.Log(Message)
End Sub
The logger class performs the following.
Append message to to a concurrent queue
Create and start a task (if no one already running) to write queue content to the file.
Set the task to nothing when completed
In the event the task is already created, the message is enqueued and the While condition in the task itself should take care of any messages added while it's running.
'Missing: Idisposable, Fileaccess.Shared,
'TODO: remove debugger.break
Public class Logger
Public Property Messages As new ConcurrentQueue(Of string)
private _WorkerTask as Task
private event WorkerTaskCompleted
private _Stream as FileStream
private _Writer as StreamWriter
Public sub New()
_Stream = io.file.OpenWrite("Mylog.txt")
_Writer = New StreamWriter(_Stream)
End sub
Public sub Log(Message as string)
Messages.Enqueue(Message)
if _WorkerTask Is Nothing
_WorkerTask = New Task(sub()
While Messages.Any
Dim CurrentMessage as string = ""
if Messages.TryDequeue(CurrentMessage)
_Writer.WriteLine(CurrentMessage)
else
debugger.Break
End If
End While
_Writer.Flush
_Stream.Flush
RaiseEvent WorkerTaskCompleted
End Sub)
_WorkerTask.Start
End If
End sub
Private Sub Logger_WorkerTaskCompleted() Handles Me.WorkerTaskCompleted
_WorkerTask = Nothing
End Sub
End Class
Please note. This is my approach to this problem but I do not have anything similar implemented and tested. Therefore, you will have to make your tests to confirm it is working properly.

Is assigning an object to itself a good idea?

I have two classes, RecordSet and Record. RecordSet has a Generic List(Of Record).
I can add objects to the list by calling my RecordSet.AddRecord(ObjRecord) function, which returns RecordSet. When the list has a count of 200, some processing occurs and a new RecordSet object is returned, otherwise itself is returned and the application can carry on adding Record objects to the list.
My concern is that there will be 200 objects of RecordSet until garbage collection does it's sweep. Is this a good idea?
Public Class RecordSet
Private lstRecords As New List(Of Record)
Public Function AddRecord(SomeVariable) AS RecordSet
lstRecords.Add(New Record())
If lstRecords.Count = 200 Then
Me.ProcessTheRecords()
Return New RecordSet()
Else
Return Me
End If
End Function
Private Sub ProcessTheRecords()
'Do stuff in here
End Sub
Private Class Record
Public Sub New()
End Sub
End Class
End Class
Then in my application I call:
Dim objRecordSet AS New RecordSet
For Each VariableName In SomeList
objRecordSet = objRecordSet.AddRecord(VariableName)
Next
'Process the remaining objects in objRecordSet here.
First of all, this is really bad pratice, it's hard to follow the code for someone new and is a potential bug source. Instead of returning urself every time, change your design.
Change your function to this:
Public Sub AddRecord(SomeVariable)
lstRecords.Add(New Record()) <--- should't you be doing something with SomeVariable?!
If lstRecords.Count = 200 Then
Me.ProcessTheRecords()
end if
End Function
Private Sub ProcessTheRecords()
'Do stuff in here
Me.lstRecords.clear()
End Sub
Now AddRecord does exactly what it says it does - it adds a new record and modifies the recordSet. ProcessTheRecords does the processing, as its supposed to do, and if u need to clear the list container - oh well, just clear it.
I strongly recommed to read this wiki article about
Cohesion.
Just as a proposiontion, the AddRecord could be a function of return type Boolean, which indicates the success of the operation (maybe an error or exception can be raised by the processing function?).
It's much cleaner now, isn't it?

Testing if object Is Nothing results in 'Object required' error

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.

Capturing the output of a ASP template for unittesting

I'm trying to find a way to capture the response of ASP templates for testing purposes. After reading this post i was hoping that the following code would provide a solution:
class cMockResponse
public data
public sub write( value)
if isempty(data) then data = ""
data = data & value
end sub
end class
class cView
public response
private sub class_initialize()
set response = new cMockResponse
end sub
public sub render()
' expected that the following would be compiled to response.write "hello world"
%> hello world <%
end sub
end class
set view = new cView
call view.render()
response.write "the mock respone was:" & view.response.data
Given the blog post i hoped that
%> hello world <%
would be simply translated to
response.write "hello world"
Since response references the mock object I hoped that this solution would do the trick, but clearly it doesn't. The output of the above code is unsurprisingly:
hello world the mock response was:
Are there other methods to capture the output of ASP templates programatically without resorting to internal xmlhttp requests?
As far as I am aware of it is not possible to capture the output.
If you require unit testing for classic ASP you might have a look at ajaxed

Resources