Session Context / Reference

I’d like to ensure that I’m appropriately referencing Session so have a question or two:

If I am executing a method in a module (ie outside of the session class but being run in its context), what is the safest way(s) to reference the Session ?

At various times in others code I have seen this:

Dim s as session = session <-- local var is faster
....
Use s

AND

session.db
session.whatever..

What about having those methods as part of the Session object - assume that’d be best but will always have some code outside so interested in hearing any advice :slight_smile:

Thanks,
Steve

Are there any opinions on this or best practices ? @Greg_O_Lone interested in hearing your thoughts in particular. I’m slightly paranoid about cross-session pollution and naturally speed is also a driver for this thread.

Ok, first of all, the global Session is a method, not an object. When referring to it from within a Session object (the one you see in your project) you should refer to it as Self. Anywhere else, use Session.

Second, if you will be referring to the session a lot, create a local variable (as you have done above with dim s as Session) to prevent calling the method more than once. The reason for this is that the global method can be an expensive call cpu-wise.

Third, if you’re thinking about creating a property on a class in or Module of type Session or WebSession, don’t… and especially don’t name it Session. Bad things happen when you hold hard references to Sessions, ranging from leaking Sessions themselves (preventing them from being destroyed) to leaking data between sessions.

Now it’s worth keeping in mind whenever code is running, what the context is at that very moment.

If the code is running as a result of an event on any instances of the built-in classes whose names start with “Web” you can pretty much be sure that the code is running in the context of a session. That is, calling the Session method will refer to the session of the browser which triggered the event.

Any other code, particularly events on objects like Timer, any of the TCPSocket subclasses, Shell objects, Thread and the App class itself have no idea about context. In other words, when events fire, it has no idea what, if any, session is also currently running code. This is part of the reason for WebThread and WebTimer exist, because they have been modified so they can figure out what the session is that they belong to.

Once you know the context, you can figure out whether you need to do anything special to access a session. If you’re in a session context, there’s nothing to do. If you’re not, you will need to give the framework a hint by creating a WebSessionContext. New in Web 2.0, it is possible to create a session context using just the identifier of a session. Let’s say you’re creating a class that needs to know which session it is connected to. In the class, you’d add a private property, maybe call it mSessionID. In the Constructor, you could write mSessionID = Session.Identifier. Then whenever you need to access the session, you should first create a local property (in code) so it will automatically be destroyed when it goes out of scope:

var ctx as New WebSessionContext(mSessionID)

  • If you’re already in the session that matches the identifier, it’ll do nothing
  • if a session with the supplied ID doesn’t exist, an exception will be raised.
  • If the supplied ID doesn’t match the current session, an exception will be raised.
  • otherwise, a context is created and you can continue.

Now there’s a lot of confusion about what WebSessionContexts are, so I should probably clear that up now. WebSessionContexts are a hint to the web framework to help it resolve which Session instance (and thereby browser) it should be communicating with at any given time. Creating a WebSessionContext instance adds it to the top of a global stack of contexts and destroying one (or letting it go out of scope) removes it from the stack. It’s very important to understand that when code is running that did not originally come from within a session, it will always be sent to the context that was last added to the stack.

If you are using multiple contexts, always check that session.Identifier matches the identifier you expect, or even better, just don’t mix contexts.

3 Likes

Now with all of that said, in web 2, we’ve made it harder to cross contaminate Sessions, but it also means that if you want to send info to another session, you’ll need to do a little more work.

The easiest way to do this is to use a Timer (not a WebTimer) as a property on the App class or in a module somewhere which fires periodically, looking for messages to send to sessions. I like to use JSON for this because it’s easy to reconfigure the data structure without having individual classes, but that’s up to you. Mostly what you need is a way to store a SessionID, a command and one or more parameters. In the place where you have the Timer, make property that’s an array of JSONItem and a method (we’ll call it Send) which takes three parameters, sessionID as string, methodName as string and parameters as jsonitem. In the method, just create a jsonitem using those three parameters and put it on the end of the array. In the Timer’s Action event, pull the first item from the array (index zero) create a WebSessionContext using the SessionID and then call a method on the Session object that takes the method and the parameters.

This method should keep you out of trouble in this regard, and I believe the Push Example project in the Example Projects > Web does something similar to this.

2 Likes

Great thank s @Greg_O_Lone for the comprehensive replies - they have clarified a lot for me and I’m sure others :+1:

1 Like

Oh and please… while it’s perfectly legal to do this, just don’t:

Var session as Session = Session

It’s confusing and can make debugging very confusing.

:wink:

1 Like

No problem. If you have any other questions, please don’t hesitate to ask!

2 Likes