#1 Re: mORMot 2 » AccessViolation in IsObjectDefaultOrVoid » 2024-06-18 15:18:47

Yes of course. I have a Data field in my working project. Its structure depends on the context of the object. I use TDocVariant with it.

The my error in the test project rather refers to the categorys of copy/past and misty eyes.

#2 Re: mORMot 2 » AccessViolation in IsObjectDefaultOrVoid » 2024-06-18 12:05:20

Found the cause of the errors. mORMot does not know how to work with parameters in the methods of services of the "array of const" type.

Thank you all.

#4 Re: mORMot 2 » AccessViolation in IsObjectDefaultOrVoid » 2024-06-17 08:16:31

I'm sorry. I didn't think the code in the post belonged to the HUGE category.

I prepared a project that I used to test/study mORMot2 where the named error is reproduced.  I will be grateful if someone has the time and desire to check the code of the program and help me with the cause of the error.

https://drive.google.com/file/d/1-HJb4U … sp=sharing

#5 mORMot 2 » AccessViolation in IsObjectDefaultOrVoid » 2024-06-14 13:36:34

-Pol_S-
Replies: 6

Hi!
I plan to update my project from M1 to M2. I try to start with a small test. But something went wrong. The code is not complex, but it does not work.

Declaration from unit DBInfo_Unit.pas:

  ...........  
  TDBInfo = class(TSynAutoCreateFields)
  private
    fDBID      : TDBID;
    fDBName    : TDBName;
    fDBFile    : TDBFile;
    fCreateDate: TTimeLog;
    fLastOpen  : TTimeLog;
    fData      : string;
    fArr       : TDocArray;
    fColl      : TCollTests;
  public
    function Documents: TDynArray;
    procedure FromORM(ormDBInfo: TOrmDBInfo);
  published
    property DBID      : TDBID read fDBID write fDBID;
    property DBName    : TDBName read fDBName write fDBName;
    property DBFile    : TDBFile read fDBFile write fDBFile;
    property CreateDate: TTimeLog read fCreateDate write fCreateDate;
    property LastOpen  : TTimeLog read fLastOpen write fLastOpen;
    property data      : string read fData write fData;
    property DocArray  : TDocArray read fArr write fArr;
    property Coll      : TCollTests read fColl;
  end;

  TDBInfoArray = array of TDBInfo;

  IDBInfoService = interface(IInvokable)
    ['{495A2BC3-E1EB-45BD-9ABB-B1F6B1395E74}']
    function Add(var aDBInfo: TDBInfo): TServiceResult;
    function GetOne(var aDBInfo: TDBInfo; FindBy: TFindBy): TServiceResult;
    function GetWhere(const aWhere: string; const BoundsWhere: array of const; var aDBInfoArr: TDBInfoArray; var Count: Integer): TServiceResult;
    function Update(const aDBInfo: TDBInfo): TServiceResult;
    function Delete(const aID: TID): TServiceResult;
    function TotalCount: Integer;
  end;

  /// ORM class corresponding to TDBInfo
  TOrmDBInfo = class(TOrm)
  protected
    fDBName    : string;
    fDBFile    : string; 
    fCreateDate: TTimeLog;
    fLastOpen  : TTimeLog;
    fData      : string; 
    fCollVar   : string;
    fDocArray  : string;
  public
    procedure FromObject(aDBInfo: TDBInfo; IncludeId: Boolean = True);
  published
    property DBName    : string read fDBName write fDBName { stored AS_UNIQUE };
    property DBFile    : string read fDBFile write fDBFile { stored AS_UNIQUE };
    property CreateDate: TTimeLog read fCreateDate write fCreateDate;
    property LastOpen  : TTimeLog read fLastOpen write fLastOpen;
    property data      : string read fData write fData;
    property DocArray  : string  read fDocArray write fDocArray;
    property Coll      : string read fCollVar write fCollVar;
  end;

  TOrmDBInfoArray = array of TOrmDBInfo;

  TDBInfoService = class(TInjectableObjectRest, IDBInfoService)
  public
    function Add(var aDBInfo: TDBInfo): TServiceResult;
    function GetOne(var aDBInfo: TDBInfo; FindBy: TFindBy): TServiceResult;
    function GetWhere(const aWhere: string; const BoundsWhere: array of const; var aDBInfoArr: TDBInfoArray;
      var Count: Integer): TServiceResult;
    function Update(const aDBInfo: TDBInfo): TServiceResult;
    function Delete(const aID: TID): TServiceResult;
    function TotalCount: Integer;
  end;

....................

function TDBInfoService.GetOne(var aDBInfo: TDBInfo; FindBy: TFindBy): TServiceResult;
var
  ormDBInfo: TOrmDBInfo;
begin
  case FindBy of
    fbID: ormDBInfo := TOrmDBInfo.Create(server.orm, 'ID=?', [aDBInfo.DBID]);
    fbName: ormDBInfo := TOrmDBInfo.Create(server.orm, 'DBName=?', [aDBInfo.DBName]);
    fbFile: ormDBInfo := TOrmDBInfo.Create(server.orm, 'DBFile=?', [aDBInfo.DBFile]);
    fbDateCreate: ormDBInfo := TOrmDBInfo.Create(server.orm, 'CreateDate=?', [aDBInfo.CreateDate]);
    fbDateLastOpen: ormDBInfo := TOrmDBInfo.Create(server.orm, 'LastOpen=?', [aDBInfo.LastOpen]);
    fbDataInfo: ormDBInfo := TOrmDBInfo.Create(server.orm, 'CreateDate=?', [aDBInfo.CreateDate]);
  else Exit(srBadRequest);
  end;

  try
    if ormDBInfo.ID = 0 then begin
      result := srNotFound;
    end else begin
      aDBInfo.FromORM(ormDBInfo);
      result := srSuccess;
    end;
  finally
    ormDBInfo.Free;
  end;
end;

function TDBInfoService.GetWhere(const aWhere: string; const BoundsWhere: array of const; var aDBInfoArr: TDBInfoArray;
  var Count: Integer): TServiceResult;
var
  Results  : TOrmDBInfoArray;
  ormDBInfo: TOrmDBInfo;
  aList    : IList<TOrmDBInfo>;
  DA       : TDynArray;
  Idx      : Integer;
begin

  //  ormDBInfo := TOrmDBInfo.CreateAndFillPrepare(server.orm, ToUTF8(aWhere), BoundsWhere);
  //  try
  //    DA := DynArray(TypeInfo(TDocArray), aDBInfoArr);
  //    while ormDBInfo.FillOne do begin
  //      Idx := DA.Add(TDBInfo.Create);
  //      aDBInfoArr[Idx].FromORM(ormDBInfo);
  //    end;
  //    Count := DA.Count;
  //    result := srSuccess;
  //  finally
  //    ormDBInfo.Free;
  //  end;

  //  if server.orm.RetrieveIList(TOrmDBInfo, aList, ToUTF8(aWhere), BoundsWhere) then begin
  //    Count := aList.Count;
  //    SetLength(aDBInfoArr, Count);
  //    for var I := 0 to Count - 1 do begin
  //      aDBInfoArr[I] := TDBInfo.Create;
  //      aDBInfoArr[I].FromORM(aList[I]);
  //    end;
  //    result := srSuccess;
  //  end else result := srBadRequest;

  if server.orm.RetrieveListObjArray(Results, TOrmDBInfo, ToUTF8(aWhere), BoundsWhere) then begin
    try
      Count := Length(Results);
      SetLength(aDBInfoArr, Count);
      for var I := 0 to Count - 1 do begin
        aDBInfoArr[I] := TDBInfo.Create;
        aDBInfoArr[I].FromORM(Results[I]);
      end;
      result := srSuccess;
    finally
      ObjArrayClear(Results);
    end;
  end
  else result := srBadRequest;
end;

Using In main unit:

    CoreModel := TOrmModel.Create([TOrmDBInfo, TAuthUser, TAuthGroup]);
    CoreDBClient := TRestClientDB.Create(CoreModel, nil,  '_TestDBInfo_M2.db3',  TSQLRestServerDB,  True,   ''  );

    // Server
    with CoreDBClient.server do begin
      db.Synchronous := smOff;
      db.LockingMode := lmExclusive;
      CreateMissingTables;
      AuthenticationRegister(TRestServerAuthenticationDefault);
      ServiceDefine(TDBInfoService, [IDBInfoService], sicShared  );
    end;

    // Client
    Check('CoreDBClient.SetUser', CoreDBClient.SetUser('Admin'  , 'synopse'));
    Check('CoreDBClient.ServiceDefine', CoreDBClient.ServiceDefine([IDBInfoService], sicShared ));

............

    Bool := aRest.Services.Resolve(IDBInfoService, cmd);
    if Bool then begin
       for i := 1 to MAX do begin
           DBInfo.DBName := 'Template' + I.Tostring;
           Check('GetOne DBName="' + DBInfo.DBName + '"', cmd.GetOne(DBInfo, fbName) = srSuccess);
       end;

       Check('GetWhere Name = Template_1*', cmd.GetWhere('DBName LIKE ?', ['Template_1%'], DBInfoArr, Count) = srSuccess);
    end;

GetOne work fine. GetWhere's use gives an error  even before entering the implementation. In Log:

20240614 15454602 EXCOS EAccessViolation (c0000005) [Main] at f19c4d mormot.core.rtti.pas IsObjectDefaultOrVoid (9423)  mormot.core.rtti.pas TRttiCustom.ValueIsVoid (8078) mormot.core.json.pas _JS_RttiCustom (5781) mormot.core.interfaces.pas TInterfaceMethodArgument.AddJson (2719) mormot.core.interfaces.pas TInterfacedObjectFake.FakeCallGetJsonFromStack (3442) mormot.soa.client.pas TInterfacedObjectFakeClient.FakeCallGetJsonFromStack (502) mormot.core.interfaces.pas TInterfacedObjectFake.FakeCallInternalProcess (3544) mormot.core.interfaces.pas TInterfacedObjectFakeRaw.FakeCall (3307) 

Am I doing something wrong or missing something?

#6 mORMot 1 » CallbackRelease and Session close » 2021-03-30 09:58:32

-Pol_S-
Replies: 0

Hi there. I use callbacks and services via interfaces and websockets. Schematically, the code looks like this:

 
IBoss = interface(IInvokable)
   function Manager1:IManager1; // create or return Manager1
   function Manager2:IManager2; // create or return Manager2
end;
...
destructor TBoss.Destroy;
begin
  fMng2 := nil;
  fMng1 := nil;
  inherited;
end;
...

//The difference between Manager1 and Manager2 in services. Therefore, the schematic code is for one only.

IManager1 = interface(IInvokable)...

TManager1 = class(TInterfacedObjectWithCustomCreate, IManager1)
   ...
   fMService  : IMService1; // interface(IServiceWithCallbackReleased)
   fMCallback : IMCallback1;
   fClient    : TSQLRest;
   ...
end;

TMCallback1 = class(TInterfacedCallback, IMCallback1)
  private
    fMng:TManager1;
  public
    constructor Create(Manager:TManager1; aRest: TSQLRest; const aGUID: TGUID); reintroduce;
   ...
end;

constructor TManager1.Create;
begin
  inherited Create;
  fClient := TRestClient.Instance.Client;
  fMService := fClient.Service<IMService1>;
  fMCallback := TMCallback1.Create(Self, fClient, IMCallback1);
  fMService.Subscribe(fMCallback);
  ...
end;

destructor TManager1.Destroy;
begin
   fMCallback := nil;
   fMService := nil;
   ...
   inherited;
end;

When the program completes work with the "Boss", the following code is executed

...
Boss := nil;
TRestClient.Instance.Disconnect;
...

And... The session closes faster than the server has time to perform the required actions related to the CallbackRelease.
The log looks something like this:

15250718  +    mORMotHttpClient.TSQLHttpClientWebsockets(03986e90).Callback svc/CacheFlush/_callback_
15250718  +        mORMotHttpClient.TSQLHttpClientWebsockets(03986e90).InternalURI POST
15250718 trace         mORMotHttpClient.TSQLHttpClientWebsockets(03986e90) InternalRequest POST calling THttpClientWebSockets(039ec450).Request
15250718 clnt          mORMotHttpClient.TSQLHttpClientWebsockets(03986e90) POST svc/CacheFlush/_callback_?session_signature=66ab3c2d00014be19865d723 status=200 len=0 state=0
15250718  -        00.000.022
15250718 ret       mORMotHttpClient.TSQLHttpClientWebsockets(03986e90) POST result=200 resplen=0
15250718  -    00.000.032
15250718 trace mORMotHttpClient.TSQLHttpClientWebsockets(03986e90) SessionClose: notify server
15250718  +    mORMotHttpClient.TSQLHttpClientWebsockets(03986e90).CallBackGet svc/Auth?UserName=Admin&Session=1722498093
15250718  +        mORMotHttpClient.TSQLHttpClientWebsockets(03986e90).InternalURI GET
15250718 trace         mORMotHttpClient.TSQLHttpClientWebsockets(03986e90) InternalRequest GET calling THttpClientWebSockets(039ec450).Request
15250719  +    TSVCServer(03976930).URI GET svc/Auth?UserName=Admin&Session=1722498093&session_signature=66ab3c2d00014be10a815db5 in=0 B
15250719 call  TSVCServer(03976930) Auth UserName=Admin&Session=1722498093&session_signature=66ab3c2d00014be10a815db5
15250719 auth  TSVCServer(03976930) Deleted session Admin:1722498093/1 from /2
15250719 srvr  TSVCServer(03976930) Admin  GET svc/Auth Method=200 out=0 B in 92us
15250719  -    00.000.110
15250719  +    TSVCServer(03976930).URI POST svc/CacheFlush/_callback_?session_signature=66ab3c2d00014be19865d723 in=22 B
15250719 auth      mORMot.TSQLRestRoutingREST(02f6eea0) AuthenticationFailed(afInvalidSignature) for svc/CacheFlush/_callback_?session_signature=66ab3c2d00014be19865d723 (session=1722498093)
15250719 debug     TSVCServer(03976930) TSQLRestRoutingREST.Error: {  "errorCode":403,  "errorText":"Authentication Failed: Invalid signature (0)"  }
15250719 srvr      TSVCServer(03976930)   POST svc/CacheFlush ?=403 out=82 B in 35us
15250719  -    00.000.047
15250719  +    TSVCServer(03976930).URI POST svc/CacheFlush/_callback_?session_signature=66ab3c2d00014be19865d723 in=26 B
15250719 auth      mORMot.TSQLRestRoutingREST(02f6eea0) AuthenticationFailed(afInvalidSignature) for svc/CacheFlush/_callback_?session_signature=66ab3c2d00014be19865d723 (session=1722498093)
15250719 debug     TSVCServer(03976930) TSQLRestRoutingREST.Error: {  "errorCode":403,  "errorText":"Authentication Failed: Invalid signature (0)"  }
15250719 srvr      TSVCServer(03976930)   POST svc/CacheFlush ?=403 out=82 B in 23us
15250719  -    00.000.034
15250719 clnt          mORMotHttpClient.TSQLHttpClientWebsockets(03986e90) GET svc/Auth?UserName=Admin&Session=1722498093&session_signature=66ab3c2d00014be10a815db5 status=200 len=0 state=0
15250719  -        00.013.979
15250719  -    00.013.983
15250719 info  mORMotHttpClient.TSQLHttpClientWebsockets(03986e90) TSQLRest.Destroy svc
15250720 trace mORMotHttpClient.TSQLHttpClientWebsockets(03986e90) TInterfacedObjectFakeClient(0449c7a0).Destroy IMService1
15250720 trace mORMotHttpClient.TSQLHttpClientWebsockets(03986e90) TInterfacedObjectFakeClient(0449cab8).Destroy IMService2
15250720 trace mORMotHttpClient.TSQLHttpClientWebsockets(03986e90) InternalClose: fSocket.Free
15250721 trace TSVCServer(03976930) EndCurrentThread(TWebSocketServerResp) ThreadID=3060 ThreadCount=0

"Sleep(100)" after "Boss:=nil" helps, but it's not the ideal way. Is there any way to tell the client that the server has done its job and you can close the connection?

Board footer

Powered by FluxBB