Sessions and Modules

Hi all,

I have modules where many methods use the Session.

Some questions please:

  • How the module knows the session to use?
  • A good rule is to pass the session as a parameter to methods of modules?

Thank you
Olivier

If you call Session.whatever from a module, it’s sniffing the stack to figure out what Session object to use. Personally, I’m not a fan of that. If you started using WE when it was first released, and used the Session pseudo-global as intended and liberally, you’ve most certainly run into bugs and fixes and new bugs, etc. And there are some situations (push scenarios) where even if Session gets the correct Session, it might not get the one you really intend.

So with that, I would be explicit wherever you can. In a module method, that may mean passing a sess as Session parameter.

Thank you Brad. Indeed, it seems like a good rule.

I have a module with a lot of database methods. These methods use only one object of the session: session.db (database).

In your opinion, in this case, it is better to pass sess as session parameter, or db as session.db parameter?

This is totally arbitrary, but my coding style would dicate that if the method is operating on the Session, pass the Session, and if it’s operating on the database, pass the database. A coding style that passed the Session for all those could certainly be reasonable as well. Consistency is most important.

Ok, thank you Brad!

I realize that I have really a lot of methods in modules that directly call the session, including all methods of database. (the session is not passed as a parameter, it is called directly in the module)

This is a huge job to fix all of these methods.

Even with the latest versions, there are always weaknesses with sessions?

There are two features of Web Edition that are wonderful for newbie accessibility, but have proved problematic for real applications. These are the Session pseudo-global and implicit instances of web pages. The docs at this point pretty much steer developers away from implicit instances. I feel as strongly about the Session pseudo-global. Some may feel different. Even assuming they get it to work to spec, it’s still very easy to end up with the wrong Session in push situations, with one Session directly or indirectly calling methods of another.

If I had a whole bunch of mostly working source code sitting around, I’d think in terms of costs and benefits. The benefit of converting would be zero ambiguity, zero mistakes with which Session you’re referring to. The costs are the work of adding those parameters and converting. Going forward though, I’d always make room for a Session parameter to module functions that call into a Session.

ok, I must correct then, I have no choice :frowning:

I think putting a session property for each window. In the Open Event of the window, I put:

self.sess=session

That way I can use this reference in all my methods of the window, and all methods module called from the window.
This makes sense?

For those who read us, Thom said something important also:

[quote=Thom McGrath]Session is both a method and a class. When you call Session.Whatever, you’re really calling Session().Whatever. So you have the method overhead to worry about, and the fetch time. We need to figure out which session is the correct one each and every time.

If there is a bug in how we’re detecting which session belongs to which thread (all user events are threaded) then in theory, what is returned from Session() could change through the execution of your event. Threads will yield to other threads at loop boundaries, and you’ve got plenty in a time consuming process.

I’d recommend adding this to the top of your WebPage1.Button1.Action event:

Dim Session As Session = Session

This will store a local reference to the Session object returned at the beginning of the event. All other calls in your code will now reference Session the variable instead of Session the method. This will improve performance, and could work around the problem you’re seeing.[/quote]

It was in December 2012, I do not know if this recommendation is still valid with the latest updates.

Outside modules, there is no problem with sessions?

[quote=34150:@olivier vidal]ok, I must correct then, I have no choice :frowning:

I think putting a session property for each window. In the Open Event of the window, I put:

self.sess=session

That way I can use this reference in all my methods of the window, and all methods module called from the window.
This makes sense?[/quote]

That probably won’t work. At best, you’ll end up creating a circular reference and your app won’t be able to release unused sessions properly. Remember, there is an instance of WebPage1 for each user, so you can’t simply call WebPage1.sess without knowing the code path that gets you to that call. If the call comes via a request from a browser, you’ll probably be okay, but if the call comes from a thread or something like a socket event, the framework won’t even try to guess (anymore).

Thank you Greg. :slight_smile:

But this reference is only used:

  • Inside the window (EDIT: not in a thread or socket)
  • Calls for database methods (module) from the window

To enhance the strength of the session and to improve the speed, since the session is sought once for all methods of the window and calls of database methods from this windows (there may be a large number of calls to the session in a window and transactions).

Whenever the user leaves a window, I destroy this window.

it is not relevant?

yes, precisely. As I want to work with the same session of the user who opened the window, it seems my be a good choice.

I do not understand.

[code]WebPage1.open:
self.sess=session

WebPage1.shown:
sess.myProperty=1
dim rs as recordset=dataModule.findData(sess, …)
[/code]

Why is it dangerous?: For the framework self.sess=session is equivalent to mysession.mywindow.mysession ?

Another interesting info of Thom (found in the NUG):

[quote=Thom McGrath]
Sessions are defined in code like this:

Module Session Function Session () As Session // Find the current session End Function Class Session Inherits WebSession End Class End Session

So when you call Session.Identifier, you’re actually calling Session.Session().Identifier. This means the framework has to look up the session again, even though you’re already in the object you’re looking for. The most events, this is merely inefficient. In close, though, I’m pretty sure the session object is already out of the stack so Session.Session() will return nil.

You should use Self inside any session code. In fact, outside of session code, if you’re calling Session often inside a single method, consider code such as:

Dim Session As Session = Session

And now you’ll lookup Session only once in the method, and won’t have to change any code. Even though the line of code appears completely insane.[/quote]

I am very concerned about these session issues. Some experiences to share with sessions?

Oliver, on what Greg was referring to… use a WeakRef to a Session if you’re going to cache it in a WebPage property (for example). That will avoid the circular references. Overall, I guess I’d recommend that if the Session pseudo-global feels like “magic” to you, either accept that it’s magical (with all the downstream problems that will probably entail) or do your best to really understand its behavior.

The bottom line on the Session pseudo-global for me is that it makes Web Edition approachable, but even assuming it is bug free at this point, once you get into push scenarios, it gets completely counterintuitive. You will avoid problems by finding the Session object you want and passing it as a parameter where it needs to be used.

I’ve just send you an email about it! I studied your session solution in Web Essentials today, it is interesting, I think I’ll actually apply. :slight_smile:

Regarding Thom’s suggestion of

Dim Session as Session = Session

I suggest that you NOT do that. We have code like that in several places and it makes it really hard to fix bugs because you can’t get to the global method, even if you wanted to. If you need this, use a different variable name.

Greg, thank you very much for the warning!

Previously, I put this code in many places.
But in the end, I opted for the solution of Brad (http://www.studiostable.com/webessentials).