Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
TIWUserSession or TUserSession
#1
I have some SA programs that have worked for years and am in the process of moving to a different host system which runs in a virtual machine. Some of my Intraweb 15 programs run fine but others crash every night on the VM, even though, to the best of my knowledge I designed them all the same way and they never did so on the old physical machine. Original code was developed in Intraweb 5 with changes where forced on me during compiling since then as I have moved to more recent versions of Intraweb.

I am wondering whether part of the issue may be due to the way I use TUserSession rather than TIWUserSession in many cases because I have multiple datamodules in each program.

What exactly is the purpose and difference between a UserSession and a IWUserSession. Recent examples in the Intraweb documentation use a UserSessionUnit which is mostly based on TIWUserSession and declare links to datamodules within this. Is it better to do things this way or should it not matter?

Any suggestions for ways to improve or implement a currently preferred way to do things would be appreciated. I have also noted in various documentation that since IW 14 one should declare the aSession as a descendent of TIWUserSession with (nil, aSession) but, since I use UserSessions, this does not compile.

My current general program structure is to have, say, two datamodules with definitions something like the following

unit datamodule1;
interface
uses
  various items listed here;
type
  Tdatamodule1 = class(TDataModule)
    various data components;
  private
  public
  published
  end;

function datamodule1: Tdatamodule1;

implementation

use
  various items here;

function datamodule1: Tdatamodule1;
  Result := TUserSession(WebApplication.data).datamodule1;
end;

various procedure here;

end.


In the ServerController unit I have:

unit ServerController;

interface
uses
  datamodule1name, datamodule2name,
  various other items listed here;
type
  TIWServerController = class(TIWServerControllerBase)
    procedure IWServerControllerBaseNewSession(aSession: TIWApplication);
    procedure IWServerControllerBaseGetMainForm(var vMainForm: TIWBaseForm);
    various data components;
  private
  public
  end;

  TUserSession = class(TComponent)
  public
    MainForm : TMainForm;
    datamodule1 : Tdatamodule1;
    datamodule2 : Tdatamodule2;
    various other usersession items defined here;
  end;

  function UserSession: TUserSession;
  function IWServerController: TIWServerController;

implementation

uses
   various items defined here;

function IWServerController: TIWServerController;
begin
  Result := TIWServerController(WebApplication.Data);
end;

function UserSession: TUserSession;
begin
  Result := TUserSession(WebApplication.Data);
end;


procedure TIWServerController.IWServerControllerBaseGetMainForm(var vMainForm: TIWBaseForm);
begin
  vMainForm := TMainForm.Create(WebApplication);
end;

procedure TIWServerController.IWServerControllerBaseNewSession(aSession := TIWApplication);
begin
  aSession := TUserSession.Creat(nil);
end;


procedure TUserSession.Destroy;
begin
  various items get destroyed here;
  inherited Destroy;
end;

end.
Reply
#2
Hi Bruce,

Let's start with UserSession and related stuff:

TIWUserSession is the class declared in unit UserSessionUnit.pas. When you create a new IW application, a new UserSessionUnit.pas file is automatically created for you by IW Application Wizard.

UserSession is a function declared in unit ServerController. The function UserSession returns the TIWUserSession instance for that specific session.

Remember that when you have "N" users (sessions) using your application, you also have "N" instances of TIWUserSession class, each one belonging to a specific application user session.

So, when you call the function UserSession from your code, you will always get the TIWUserSession instance for the current session, no need to worry about it because IW will take care of the complications for you.

The same instance is also stored in the property named "Data" of TIWApplication.

That's why

WebApplication.Data = UserSession()    // remember -> UserSession() here is the function declared in ServerController.pas

Personally I wouldn't create anything named TUserSession because I find it very confusing with existing TIWUserSession and UserSession() already declared in every IntraWeb application.

I would definitely look for another name....

Also, I personally like to make my DataModules available through existing TIWUserSession, as properties. Like this:

Code:
type
  TIWUserSession = class(TIWUserSessionBase)
  private
    { Private declarations }
    FDataModule1: TDataModule1;
    function GetDataModule1: TDataModule1;
  public
    { Public declarations }
    property DataModule1: TDataModule1 read GetDataModule1;
  end;

implementation

{$R *.dfm}

{ TIWUserSession }

function TIWUserSession.GetDataModule1: TDataModule1;
begin
  if not Assigned(FDataModule1) then
    FDataModule1 := TDataModule1.Create(Self);
  Result := FDataModule1;
end;

Please notice that here I'm creating the DataModule on demand, i.e. it will be instantiated only when referenced the first time. Also important to notice that the owner of the DataModule is always the UserSession itself. This has 2 advantages: (a) I don't need to write code to free it and (b) IntraWeb will take care of freeing it for me when destroying the session.

Also, doing that way, the DataModule1 can be referenced from anywhere in my application like this:


Code:
dm := TIWUserSession(WebApplication.Data).DataModule1;  // using WebApplication which is a property of many controls, IWForm, etc.

or

dm := UserSession.DataModule1;   // using UserSession() function from ServerController.pas, which must be added to the uses clause


Which makes it vary handy.

Another thing I do all the time is connecting DataSources and DataSets (in my DataModule1, for instance), via code, inside OnCreate events of IWForms. So I have:

Code:
TIWForm1 = class(TIWAppForm)
  private
    FDataModule1: TDataModule1;
  public
  end;

implementation

{$R *.dfm}

procedure TIWForm1.IWAppFormCreate(Sender: TObject);
begin
  FDataModule1 := TIWUserSession(WebApplication.Data).DataModule1;  // or UserSession.DataModule1 if you add ServerController to the uses clause

  DataSource1.DataSet := FDataModule1.Query1;
  DataSource2.DataSet := FDataModule1.Query2;
  DataSource3.DataSet := FDataModule1.Query3;

 // and so on
end;

This has 2 main advantages: (a) Makes sure that my components are always connected (sometimes you save a form and it loses the reference to another component in another container) and (b) it performs better when creating the form because the code which loads the form from DFM doesn't have to find the component in another DataModule and connect them.

Organizing your application this way I find it very hard to have anything crashing because the lifetime of all objects is handled by IntraWeb itself, with zero user code.
Reply
#3
Alex, that would make a good blog post.

Dan
Reply
#4
(08-23-2020, 06:02 AM)DanBarclay Wrote: Alex,  that would make a good blog post.

Dan

+1 Vote
Reply
#5
(08-23-2020, 06:02 AM)DanBarclay Wrote: Alex,  that would make a good blog post.

Dan

Hi Dan,

Yes, that sounds a good idea. I'm working on it :-)

Cheers
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)