From a Container Control on a WebPage, I send a POST request to an API on a service I have subscribed to. The response comes back in the PageReceived event of the HTTPSecureSocket instance on the WebPage. In the PageReceived event, I call a public method of the Container Control to get the response data back into the Container. When the ccRegisterNewAccount1.PageReceived method is called from the HTTPSSignin.PageReceived event, the data is passed correctly but I lose the Session object. Why?
My understanding is that the code in the PageReceived event is running in a different thread and is not aware of which Session to reference. To address this, use WebSessionContext or store a reference to the Session in a Property on the WebPage that has your HTTPSecureSocket instance.
Reading through the document, I understand what the WeakRef but am left confused at how to use it in my scenario.
I have added a refNewAccount As WeakRef property to my WebPage that contains the Container Control (ccRegisterNewAccount1). I then added refNewAccount = new WeakRef(me) to the Open event of ccRegisterNewAccount1. I assume this will set the “Value” property to a reference of the ccRegisterNewAccount1 Container Control. If this is correct, the thing I don’t understand is how to reference the ccRegisterNewAccount1.PageReceived public method using the refNewAccount object reference.
My comment was in response to Fred’s suggestion about keeping a reference to a Session on the socket. Basically the problem is that you have a reference to the socket in your session and a reference to the Session in the socket. This is called a circular reference and because of them your app “leaks memory”. Basically, neither of the objects (the Session or the Socket) can ever be destroyed because they both hold onto the last reference to the other. If Sessions don’t die, neither do any other properties, pages or controls that were open when the user leaves your app.
The solution I like to use is to use a Computed Property which sets a WeakRef in the background. On your Socket:
[code]Property mSession as WeakRef
Computed Property MySession as Session
Sub Set (value as WebSession)
mSession = New WeakRef(value)
End Sub
Function Get() as WebSession
If mSession = nil or mSession.value = nil then
return nil
else
return WebSession(mSession.Value)
End If
End Function[/code]
When you create the socket, set the socket’s MySession property. Whenever you want to reference the session, make a copy, check to see if it’s nil and if it’s not, then go ahead and use it. if it’s nil, you can probably stop what you’re doing with the socket because the Session is already gone:
Dim sess as WebSession = MySession
if sess<>nil then
sess.webpage1.progressbar1.value = xxxxx
end if
On the HTTPS1 Super, create the private property mSession as well as the Computer Property MySession
Set HTTPSSignIn.MySession = Session in the ccRegisterNewAccount1.SendHTTPSPostRequest event
Call HTTPSSignIn.Post
Then in HTTPSSignIn.PageReceived…
Dim sess as WebSession = MySession
if sess<>nil then
sess.pgSignin.ccRegisterNewAccount1.PageReceived(url, httpStatus, DefineEncoding(content, Encodings.UTF8))
end if
When I do this I receive the following errors when trying to run the project.
Type mismatch error. Expected class Session.Session, but got class WebSession -> Return WebSession(mSession.Value)
This item does not exist -> Dim sess as WebSession = MySession
Type “WebSession” has no member named “pgSignin” -> sess.pgSignin.ccRegisterNewAccount1.PageReceived(url, httpStatus, DefineEncoding(content, Encodings.UTF8))
Dim sess as WebSession = me.MySession
if sess<>nil then
if sess.CurrentPage Isa pgSignin then
pgSignin(sess.CurrentPage).ccRegisterNewAccount1.PageReceived(url, httpStatus, DefineEncoding(content, Encodings.UTF8))
end if
end if
This allows me to compile and run but I still receive a NilObjectException on Session.ClientTime.GMTOffset as stated in my initial post. I’m thinking it has something to do with HTTPSSignIn.MySession = Session in the ccRegisterNewAccount1.SendHTTPSPostRequest event. Am I assigning the wrong session/object?
If I change HTTPSSignIn.MySession = Session to HTTPSSignIn.MySession = WebSession I get [quote]Expected a value of type class WebSession, but found a static namespace reference to class WebSession.[/quote]
Dim sess as WebSession = me.MySession
if sess<>nil then
if sess.CurrentPage Isa pgSignin then
pgSignin(sess.CurrentPage).ccRegisterNewAccount1.PageReceived(url, httpStatus, DefineEncoding(content, Encodings.UTF8))
end if
end if
Doesn’t seem to call the PageReceived method in the calling session even though stepping through the code shows the data as entered before the call to HTTPSSignin.Post. I am assuming from the comments above that this code should pass the variables to the PageReceived method from the calling ccRegisterNewAccount1 container control and code execution should continue as normal within the original websession. So when MsgBox "PageReceived: " + CStr(Session.ClientTime.GMTOffset) is executed in the ccRegisterNewAccount1.PageReceived public method, Session.ClientTime should be referencing the original Session.
It steps through just fine to the ccRegisterNewAccount1.PageReceived event.
Sub PageReceived(url As String, httpStatus As Integer, data As String)
MsgBox Session.Identifier
MsgBox "PageReceived: " + CStr(Session.ClientTime.GMTOffset)
End Sub
I get the NilObjectException on the “Session.” object identifier yet the session was there in the previous step.
[quote]WARNING: Using pgSignin inside pgSignin is bad form and can lead to hard-to-find errors. Use Self instead.
Warning: No Session object in context[/quote]
Yes. You still can’t call Session.xxx in there because it’s being called from an event that’s not connected to a session. You can however, bring a “session” into existence using the other method Fred talked about… using WebSessionContext thusly:
Assuming your code is running on a method within a WebPage…
dim ctx as new WebSessionContext(App.SessionForControlID(self))
See this blog post that talks about WebSessionContexts:
[quote]Parameter “ControlID” expects type String, but this is class pgSignin.pgSignin
Dim ctx As new WebSessionContext(App.SessionForControlID(self))[/quote]
Dim ctx As new WebSessionContext(App.SessionForControlID(self))
HTTPSSignIn.SessionContext = ctx
pgSignin.HTTPSSignin.PageReceived
Dim ctx As WebSessionContext = me.SessionContext
if ctx <> nil then
if ctx.Session.CurrentPage IsA pgSignin then
pgSignin(ctx.Session.CurrentPage).ccRegisterNewAccount1.PageReceived(url, httpStatus, DefineEncoding(content, Encodings.UTF8))
end if
end if
HTTPS1
[code]Private mSession As WeakRef
Property SessionContext As WebSessionContext
Get
If mSession = nil or mSession.value = nil then
Return nil
else
Return WebSessionContext(mSession.Value)
End If
End Get
Set
mSession = new WeakRef(value)
End Set[/code]
Dim ctx As new WebSessionContext(App.SessionForControlID(self.ControlID))
HTTPSSignIn.SessionContext = ctx
I added .ControlID to self and now when I step through, ctx is being created at the current WebSessionContext and is successfully assigned to HTTPSSignIn.SessionContext. However, when the HTTPSSignIn.PageReceived is fired, me.SessionContext is Nil.
In HTTPSSignIn.PageReceived try replacing Dim ctx As WebSessionContext = me.SessionContext with Dim ctx As New WebSessionContext(App.SessionForControl(Self)).