Cannot access session variable - NilObjectException

Hi all,
this is slowly driving me nuts…

I’ve subclassed a DBKit.toolbar.
I’ve been able to add the extra buttons/spaces/flexiblespaces/labels I need by adding a Timer.callLater in the toolbar’s “Shown” event to ensure this is called after the DBKit.toolbar has finished loading its buttons.

The intention is to also disable some buttons if not ‘admin’
I decided to store a boolean ‘isAdmin’ in the Session. I can set it user login without issues and it sets correctly.

However I get a NilObjectException when reading this boolean:

var  users as new WebToolbarButton
users.caption = "Users"
users.tag = "users"
users.Enabled = Session.isAdmin // NilObjectException with no clue as to why
ToolbarSK.AddItem(users)

Have I done something incorrectly? is there a better way to do this? (the isAdmin flag should be accessible by multiple windows…)

Many thanks,
Stam

Timer fires its events on the main thread and not within the context of a session. Because of that, Session is Nil.

You can work around this by passing along the current Session.Identifier and creating a WebSessionContext when you need to access the session.

Thanks Greg - undoubtedly you are right… but I can’t figure out the code for this.
Trying to access instance variables doesn’t work with what I’ve tried, it only accesses class variables:

Var wsc As new WebSessionContext(App.SessionForControl(Self))
var currentSession as webSession =  wsc.Session
users.Enabled = currentSession.isAdmin // error: "type 'websession' has no member 'isAdmin'

Clearly I’m not getting this - grateful for any suggestions…

@Stam_Kapetanakis,

I believe you need to cast the returned WebSession to Session like this:

Var wsc As new WebSessionContext(App.SessionForControl(Self))
var currentSession as webSession =  wsc.Session
users.Enabled = Session(currentSession).isAdmin

See if that helps.

Note: This is from memory, “forum code” so I may have goofed something.

Anthony

1 Like

Anthony, that’s perfect - it worked fine as is!
I have no idea how I was supposed to know this - or even find this out as it didn’t appear on google searches - so truly, thank you!

Stam

@Stam_Kapetanakis - it’s not obvious, but I believe the gist of things is:

Session is a subclass and WebSession is the base class. (Greg or the Xojo team could probably give you the whys and wherefores)

This paragraph is in the docs:

Session refers to two things in your web projects. The Session class in the project is a subclass of WebSession that you can use to add your own properties, methods and constants. Each user that connects to the web app gets their own instance of the Session class, which can be conveniently accessed using the Session method. To learn about the Session class, refer to the WebSession class. This topic discusses the Session method that provides you with a reference to WebSession for the active user.

Which nudges you in the right direction, but an example of casting a WebSession to a Session under the WebSession entry would be helpful.

Glad you got your issue sorted out. :slight_smile:

Have a great day,
Anthony

1 Like

Wasn’t WebTimer supposed to solve the Session Context problem?

3 Likes

Ahh… maybe so. I had used code I found online: Timer.CallLater(<milliseconds>, addressof <method>)
I can’t check right now but will do when I have more time - thank for the tip.

Try with WebTimer.CallLater instead, it will take care of the session.

3 Likes

I’m reading this as “There’s no context of a session because it’s executed on the main thread”. I bet it’s not what you wanted to imply.

No, that is exactly what he wanted to imply. Timer <> WebTimer.

1 Like

Just to confirm that both the session(webSession) and webTimer approaches work just fine - thank you all for your help.
Stam

2 Likes

Neither of them are a secondary thread :person_shrugging:.

WebTimer runs in the session, which is a secondary thread.

Ah, we’re not talking about cooperative or preemptive threads, then. Sorry, I misread the thing.

That’s not entirely true.

When a WebTimer is created, it records the current Session.Identifier string in a property. When the event fires, it uses that identifier to create a WebSessionContext before your code runs. Technically the session code runs on the main thread, it just has a hint as to which Session the currently running code belongs to.

FWIW, you can use that technique on any of the things whose events run on the main thread. Sockets, Shells, etc. just subclass them and do what I described above.

2 Likes

Good to know.