#1 2015-05-19 07:10:52

cypriotcalm
Member
Registered: 2015-02-18
Posts: 122

interface inheritance at RegisterInterfaces internal error L2111

Hi ab,

i have the following problem. I have the source code:

  // interface I
  IPhoMessartQuery = interface(ICQRSQuery)
  ['{CCFB5FAA-FFA2-437A-849C-E7F5A57763D6}']
    function SelectByName(const AName: String): TCQRSResult;
    function Get(out AAggregate: TPhoMessart): TCQRSResult;
    function GetAll(out AAggregates: TPhoMessartObjArray): TCQRSResult;
    function GetNext(out AAggregate: TPhoMessart): TCQRSResult;
    function GetCount: Integer;
  end;

  // interface II
  IPhoMessartCommand = interface(IPhoMessartQuery)
  ['{EF721955-203E-4A3E-9FD2-B83A2939669E}']
    function Add(const AAggregate: TPhoMessart): TCQRSResult;
    function Update(const AUpdatedAggregate: TPhoMessart): TCQRSResult;
    function Delete: TCQRSResult;
    function DeleteAll: TCQRSResult;
    function Commit: TCQRSResult;
    function Rollback: TCQRSResult;
  end;

initialization
  TInterfaceFactory.RegisterInterfaces([TypeInfo(IPhoMessartQuery), TypeInfo(IPhoMessartCommand)]);

Unfortunately I can't compile it and I get an internal error L2111.
I have tried to close the project and restart the IDE in order to clear the unit cache. It didn't help.

But if I change my code in a way that the interface II inherits from ICQRSQuery, i.e.

  // interface II
  IPhoMessartCommand = interface(ICQRSQuery)
  ['{EF721955-203E-4A3E-9FD2-B83A2939669E}']
   ...
  end;

I can compile the code without problems.

Do you have an idea how I can get rid of the internal error without the changing the code?

Thank you!

Offline

#2 2015-05-19 07:59:04

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,659
Website

Re: interface inheritance at RegisterInterfaces internal error L2111

I never saw this internal error L2111.
Which version of the compiler are you using?

Are you able to compile the regression tests, and the dddInfraRepoUser unit?

This is pretty weird...

I sadly do not know how to circumvent it.
Perhaps putting a "type" between the two definitions.
Or trying to define IPhoMessartCommand in a second unit...
Or changing the GUID...

Online

#3 2015-05-19 09:00:08

cypriotcalm
Member
Registered: 2015-02-18
Posts: 122

Re: interface inheritance at RegisterInterfaces internal error L2111

ab wrote:

I never saw this internal error L2111.
Which version of the compiler are you using?

Are you able to compile the regression tests, and the dddInfraRepoUser unit?

This is pretty weird...

I sadly do not know how to circumvent it.
Perhaps putting a "type" between the two definitions.
Or trying to define IPhoMessartCommand in a second unit...
Or changing the GUID...

I am using Delphi XE3.

I have never bone before with the regression tests. Which project in the library is that?

I have tested your assumptions but without success. If I remove the code (see below), I can compile the project. Otherwise, not :-(

 initialization
   TInterfaceFactory.RegisterInterfaces([TypeInfo(IPhoMessartQuery), TypeInfo(IPhoMessartCommand)]);

Last edited by cypriotcalm (2015-05-19 09:01:55)

Offline

#4 2015-05-19 09:37:30

cypriotcalm
Member
Registered: 2015-02-18
Posts: 122

Re: interface inheritance at RegisterInterfaces internal error L2111

A generally question, I would like a domain model with interface based services. Is this a right way how I am doing that... I have followed one of your DDD examples:

I define the interfaces (see the code above in the previous posts), then I register them in the initialization section.
After that I use them like follows:

  Model := TSQLModel.Create([], ROOT_NAME);
  ServerDB := TSQLRestServerDB.Create(Model,ChangeFileExt(ExeVersion.ProgramFileName,'.db3'), False);
  ServerDB.CreateMissingTables;
  ServerDB.ServiceDefine(TPhoMessartCommand, [IPhoMessartCommand], sicShared);

  ServerHTTP := TSQLHttpServer.Create('7979', [ServerDB], '+', useHttpApiRegisteringURI);
  ServerHTTP.AccessControlAllowOrigin := '*'; // allow cross-site AJAX queries

  ...  
  ...
  var
     cmd: IPhoMessartCommand;
  begin
    ServerDB.Services.Resolve(IPhoMessartCommand, cmd);
    if Assigned(cmd) then
    begin
      // do something
    end; 
  end;

Offline

#5 2015-05-19 10:37:52

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,659
Website

Re: interface inheritance at RegisterInterfaces internal error L2111

cypriotcalm wrote:

If I remove the code (see below), I can compile the project. Otherwise, not :-(

   TInterfaceFactory.RegisterInterfaces([TypeInfo(IPhoMessartQuery), TypeInfo(IPhoMessartCommand)]);

You may safely put this line outside the initialization section of this unit, elsewhere in your code.

Online

#6 2015-05-19 10:40:20

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,659
Website

Re: interface inheritance at RegisterInterfaces internal error L2111

cypriotcalm wrote:

A generally question, I would like a domain model with interface based services. Is this a right way how I am doing that...

Yes, it sounds right.
But it will also publish the services over REST/HTTP. Is it what you meant?

You can also do IoC and DI without HTTP publication.
See http://synopse.info/files/html/Synopse% … l#TITL_157
and in practice http://synopse.info/files/html/Synopse% … l#TITL_161

Online

#7 2015-05-19 11:21:24

cypriotcalm
Member
Registered: 2015-02-18
Posts: 122

Re: interface inheritance at RegisterInterfaces internal error L2111

ab wrote:

Yes, it sounds right.
But it will also publish the services over REST/HTTP. Is it what you meant?

I am not sure yet, I hope so, I am new to all that stuff with SOA/Rest/OR-Mapping, I am learning by doing and reading ;-) What I want is to map my existing database by mORMot (data persistance), then I woud like to offer some services, e.g. "create/delete/modify a measurement art" (Domain model) and then publish these services (application). I try to follow http://synopse.info/files/html/Synopse% … #TITLE_552


Stop! :-) Maybe you are right and that's not what I want ;-)

I want actually to publish the services over REST/HTTP in a way they can be consumed by different clients (delphi, php, java etc.) So, I can't publish the delphi types, I have to do it with some kind of JSON parameters, don't I? Coud you give me a quick reference in the doc where I can read about it? It would be great!

Last edited by cypriotcalm (2015-05-19 11:31:53)

Offline

#8 2015-05-19 11:53:25

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,659
Website

Re: interface inheritance at RegisterInterfaces internal error L2111

If you use ServerDB.ServiceDefine(), then the services would be published over REST/HTTP, and data transmitted as JSON.

See http://synopse.info/files/html/Synopse% … ml#TITL_63
and http://synopse.info/files/html/Synopse% … #TITLE_404

Online

#9 2015-05-19 13:00:56

cypriotcalm
Member
Registered: 2015-02-18
Posts: 122

Re: interface inheritance at RegisterInterfaces internal error L2111

Thx for your links! The second one I havn't seen before!

I am still trying to find out the internal error. Now I have commented all the methods and step by step tested with wich methods the project can be compiled. And I have found out that that the method GetAll with my own custom data type causes the internal error.

   type
      TPhoMessartObjArray = type of TObjectDynArray;
   ...  
   ...
  IPhoMessartQuery = interface(ICQRSQuery)
  ['{CCFB5FAA-FFA2-437A-849C-E7F5A57763D6}']
    function SelectByName(const AName: String): TCQRSResult;
    function Get(out AAggregate: TPhoMessart): TCQRSResult;
//    function GetAll(out AAggregates: TPhoMessartObjArray): TCQRSResult;
    function GetNext(out AAggregate: TPhoMessart): TCQRSResult;
    function GetCount: Integer;
  end;

Do you have an idea why the internal error happens?


How do I define aggregates in a right way?

Last edited by cypriotcalm (2015-05-19 13:03:45)

Offline

#10 2015-05-19 13:50:36

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,659
Website

Re: interface inheritance at RegisterInterfaces internal error L2111

Did you register TPhoMessartObjArray via TJSONSerializer.RegisterObjArrayForJSON() ?

Online

#11 2015-05-19 14:04:30

cypriotcalm
Member
Registered: 2015-02-18
Posts: 122

Re: interface inheritance at RegisterInterfaces internal error L2111

ab wrote:

Did you register TPhoMessartObjArray via TJSONSerializer.RegisterObjArrayForJSON() ?

No!

But now I did it as follows and I don't get this annoying internal error anymore! Yeahaaa! :-) My code looks like:

type
  TPhoMessartObjArray = type TObjectDynArray;

  IPhoMessartQuery = interface(ICQRSQuery)
  ['{87BDB69C-485D-429C-A6AE-8E2751FFCFFB}']
    function SelectByName(const AName: String): TCQRSResult;
    function Get(out AAggregate: TPhoMessart): TCQRSResult;
    function GetAll(out AAggregates: TPhoMessartObjArray): TCQRSResult;
    function GetNext(out AAggregate: TPhoMessart): TCQRSResult;
    function GetCount: Integer;
  end;

  IPhoMessartCommand = interface(IPhoMessartQuery)
  ['{23BE1585-5ED9-4596-A507-A264A2FEE8F6}']
    function Add(const AAggregate: TPhoMessart): TCQRSResult;
    function Update(const AUpdatedAggregate: TPhoMessart): TCQRSResult;
    function Delete: TCQRSResult;
    function DeleteAll: TCQRSResult;
    function Commit: TCQRSResult;
    function Rollback: TCQRSResult;
  end;

implementation

initialization
  TJSONSerializer.RegisterObjArrayForJSON(TypeInfo(TPhoMessartObjArray), TPhoMessart);
  TInterfaceFactory.RegisterInterfaces([TypeInfo(IPhoMessartQuery), TypeInfo(IPhoMessartCommand)]);

Thx for your help! :-)

Last edited by cypriotcalm (2015-05-19 14:27:03)

Offline

#12 2015-05-19 14:29:16

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,659
Website

Re: interface inheritance at RegisterInterfaces internal error L2111

For you code to be really usable, you should better define:

type
  TPhoMessartObjArray  = array of TPhoMessart;

otherwise, your AAggregates[] array would be compiled as an array of TObject...
not very handy...

Online

#13 2015-05-19 14:30:48

cypriotcalm
Member
Registered: 2015-02-18
Posts: 122

Re: interface inheritance at RegisterInterfaces internal error L2111

Yep! Changed! Thx!

Offline

#14 2015-05-19 15:23:06

cypriotcalm
Member
Registered: 2015-02-18
Posts: 122

Re: interface inheritance at RegisterInterfaces internal error L2111

Dear AB!

I have another problem! :-) I setup my service server as follows

var
  PhoMessartCommandFactory: TPhoMessartCommandFactory;
begin
  FPhoRepository := TPhoDBRepository.Create;

  Model := TSQLModel.Create([TPhoMessartSQLRecord], ROOT_NAME);

  VirtualTableExternalRegister(Model, TPhoMessartSQLRecord, FPhoRepository.MDBConnectionProperties, 'messart');
  Model.Props[TPhoMessartSQLRecord].ExternalDB.MapField('ID', 'IdMessart');

  ServerDB := TSQLRestServerDB.Create(Model, ChangeFileExt(ExeVersion.ProgramFileName, '.db3'), False);
  ServerDB.CreateMissingTables;
  ServerDB.ServiceDefine(TPhoMessartCommand, [IPhoMessartCommand], sicShared);

  ServerHTTP := TSQLHttpServer.Create('7979', [ServerDB], '+', useHttpApiRegisteringURI);
  ServerHTTP.AccessControlAllowOrigin := '*'; // allow cross-site AJAX queries
end;

Everything is ok and I can start the server. The I execute the following code

var
  cmd: IPhoMessartCommand;
  MA: TPhoMessart;
  macaption: RawUTF8;
  I: Integer;
begin
    ServerDB.Services.Resolve(IPhoMessartCommand, cmd);
    if Assigned(cmd) then
    begin
      MA := TPhoMessart.Create;
      try
        for I := 1 to 10 do begin
          UInt32ToUtf8(I, macaption);
          MA.Name := 'messart #'+macaption;
          if (cmd.Add(MA) <> cqrsSuccess) then
              raise Exception.CreateFmt('Invalid data: %s',[cmd.GetLastErrorInfo]);
        end;
         //here nothing is actually written to the database
        if (cmd.Commit <> cqrsSuccess) then
            raise Exception.CreateFmt('Commit error: %s',[cmd.GetLastErrorInfo]);
         // here everything has been written to the database
      finally
        MA.Free;
      end;
    end;
end;

And I get an access violation when accessing the statement "cmd.Add(MA)". This violation happens in the unit mORMotDDD in the statement "if fPropsMapping.MappingVersion<>fPropsMappingVersion then" in the following code:

// unit  mORMotDDD 

procedure TDDDRepositoryRestFactory.AggregateToTable(aAggregate: TObject; aID: TID; aDest: TSQLRecord);
var i: integer;
begin
  if fPropsMapping.MappingVersion<>fPropsMappingVersion then
    ComputeMapping;
  if aDest=nil then
    raise EDDDRepository.CreateUTF8(self,'%.AggregateToTable(%,%,%=nil)',
      [self,aAggregate,aID,fTable]);
  aDest.ClearProperties;
  aDest.IDValue := aID;
  if aAggregate<>nil then
    for i := 0 to high(fAggregateProp) do
      AggregatePropToTable(aAggregate,fAggregateProp[i],aDest,fAggregateToTable[i]);
end;

Do you have an idea what is happening here? :-)

Offline

#15 2015-05-19 15:54:14

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,659
Website

Re: interface inheritance at RegisterInterfaces internal error L2111

How did you initialize the factory?
Did you override the constructor as expected?

Online

#16 2015-05-20 05:15:24

cypriotcalm
Member
Registered: 2015-02-18
Posts: 122

Re: interface inheritance at RegisterInterfaces internal error L2111

ab wrote:

How did you initialize the factory?
Did you override the constructor as expected?

Yes, the overriden constructor of the factory looks like

constructor TPhoMessartCommandFactory.Create(ARest: TSQLRest; AOwner: TDDDRepositoryRestManager = nil);
begin
  inherited Create(IPhoMessartCommand, TPhoMessartCommand, TPhoMessart, aRest, TPhoMessartSQLRecord, aOwner);
  AddFilterOrValidate(['*'], TSynFilterTrim.Create);
end;

But, honestly speaking, I don't know where and whether I use to use right. Can you advise me a bit?

Should I create the constructor in the following initialization code? If I create the factory, I get the access violation error anyway :-(

var
  PhoMessartCommandFactory: TPhoMessartCommandFactory;
begin
  FPhoRepository := TPhoDBRepository.Create;

  Model := TSQLModel.Create([TPhoMessartSQLRecord], ROOT_NAME);

  VirtualTableExternalRegister(Model, TPhoMessartSQLRecord, FPhoRepository.MDBConnectionProperties, 'messart');
  Model.Props[TPhoMessartSQLRecord].ExternalDB.MapField('ID', 'IdMessart');

  ServerDB := TSQLRestServerDB.Create(Model, ChangeFileExt(ExeVersion.ProgramFileName, '.db3'), False);
  ServerDB.CreateMissingTables;
  ServerDB.ServiceDefine(TPhoMessartCommand, [IPhoMessartCommand], sicShared);

  // FACTORY
  PhoMessartCommandFactory := TPhoMessartCommandFactory.Create(ServerDB);

  ServerHTTP := TSQLHttpServer.Create('7979', [ServerDB], '+', useHttpApiRegisteringURI);
  ServerHTTP.AccessControlAllowOrigin := '*'; // allow cross-site AJAX queries
end;

Offline

#17 2015-05-20 05:56:14

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,659
Website

Re: interface inheritance at RegisterInterfaces internal error L2111

Is fPropsMapping nil ?

fPropsMapping should have been set by TPhoMessartCommandFactory.Create
Why is it not the case?

Online

#18 2015-05-20 06:28:16

cypriotcalm
Member
Registered: 2015-02-18
Posts: 122

Re: interface inheritance at RegisterInterfaces internal error L2111

ab wrote:

Is fPropsMapping nil ?

fPropsMapping should have been set by TPhoMessartCommandFactory.Create
Why is it not the case?

No, fPropsMapping is not nil, the variable Factory is nil in the following code:

function TDDDRepositoryRestCommand.ORMAdd(aAggregate: TObject): TCQRSResult;
begin
  if CqrsBeginMethod(qaCommandDirect,result) then begin   
    // Factory is nil
    Factory.AggregateToTable(aAggregate,0,fCurrentORMInstance);
    ORMPrepareForCommit(soInsert,aAggregate);
  end;
end;

Offline

#19 2015-05-20 11:42:46

cypriotcalm
Member
Registered: 2015-02-18
Posts: 122

Re: interface inheritance at RegisterInterfaces internal error L2111

cypriotcalm wrote:
ab wrote:

Is fPropsMapping nil ?

fPropsMapping should have been set by TPhoMessartCommandFactory.Create
Why is it not the case?

No, fPropsMapping is not nil, the variable Factory is nil in the following code:

function TDDDRepositoryRestCommand.ORMAdd(aAggregate: TObject): TCQRSResult;
begin
  if CqrsBeginMethod(qaCommandDirect,result) then begin   
    // Factory is nil
    Factory.AggregateToTable(aAggregate,0,fCurrentORMInstance);
    ORMPrepareForCommit(soInsert,aAggregate);
  end;
end;

Ab, how do I right set this factory?

Offline

#20 2015-05-21 05:50:43

cypriotcalm
Member
Registered: 2015-02-18
Posts: 122

Re: interface inheritance at RegisterInterfaces internal error L2111

Dear AB, could you help me with this factory? Because I am stuck with that! :-(

Offline

#21 2015-05-21 10:35:57

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,659
Website

Re: interface inheritance at RegisterInterfaces internal error L2111

A factory is indeed mandatory to use the CQRS interfaces, so the following is NOT correct:

ServerDB.ServiceDefine(TPhoMessartCommand, [IPhoMessartCommand], sicShared);

You have to register the factory itself, as an IoC/DI resolver, e.g. via:

ServerDB.ServiceContainer.InjectResolver([TPhoMessartCommandFactory.Create(ServerDB)],true);

Here ...],true) would let the factory be owned by ServerDB.Services so you would not need to manually release its instance.

But you may also write:

PhoMessartCommandFactory := TPhoMessartCommandFactory.Create(ServerDB);
ServerDB.ServiceContainer.InjectResolver([PhoMessartCommandFactory ]);
...
PhoMessartCommandFactory .Free;

Note that you need the latest version of the framework source code to have access to the new TSQLRest.ServiceContainer function.
See http://synopse.info/fossil/info/cd20687e28
Otherwise, you need to have other services defined, and use TSQLRest.Services property.

I've also updated the documentation to make this point clearer:


You would probably want to use those CQRS interfaces, via usual IoC, at TSQLRest level, just like any Client-Server services via interfaces:

var cmd: IDomUserCommand;
...
  aServer.Services.Resolve(IDomUserCommand,cmd);

or, for a Query:

var qry: IDomUserQuery;
...
  aServer.Services.Resolve(IDomUserQuery,qry);

In order to be able to get a IDomUserCommand or IDomUserQuery instance from aServer.Services.Resolve(), you would need to register the TInfraRepoUserFactory first:

aServer.ServiceContainer.InjectResolver([TInfraRepoUserFactory.Create(aServer)],true);

or if you want to maintain the factory instance life-time (e.g. to share it with other interface resolvers):

var factory: TInfraRepoUserFactory;
...
  factory := TInfraRepoUserFactory.Create(aServer);
  try
    aServer.ServiceContainer.InjectResolver([factory]);
  ...
  finally
    factory.Free;
  end;
This single TInfraRepoUserFactory would allow to implement both IDomUserCommand and IDomUserQuery contracts.

Of course, having the ability to let aServer own the factory, via the InjectResolver([...],true) parameter, sounds easier to work with.

Online

#22 2015-06-17 06:42:30

cypriotcalm
Member
Registered: 2015-02-18
Posts: 122

Re: interface inheritance at RegisterInterfaces internal error L2111

Hi Arnaud,

thank you for your detailed answer!

I have tried it out, but I am getting an error. It's an access violation in the class TDDDRepositoryRestQuery. The field value Factory is nil. See the code below.

function TDDDRepositoryRestQuery.ORMSelectOne(ORMWhereClauseFmt: PUTF8Char; const Bounds: array of const; ForcedBadRequest: boolean): TCQRSResult;
begin
  CqrsBeginMethod(qaSelect,result);
  if ForcedBadRequest then
    CqrsSetResult(cqrsBadRequest) else
    CqrsSetResultSuccessIf(Factory.Rest.Retrieve(ORMWhereClauseFmt,[],Bounds,
      fCurrentORMInstance),cqrsNotFound);
end;

My server is initialized as follows:

procedure InitHTTPService;
begin
  Model := CreateModel;
  uPhoDataLayer.InitializePhoModel(Model, DatabaseConnectionProperties);

  ServerDB := TSQLRestServerDB.Create(Model, ChangeFileExt(ExeVersion.ProgramFileName, '.db3'), False);
  ServerDB.CreateMissingTables;
  ServerDB.ServiceRegister(TPhoMessartCommand, [TypeInfo(IPhoMessartCommand)], sicShared);
  ServerDB.ServiceContainer.InjectResolver([TPhoMessartCommandFactory.Create(ServerDB)], True);

  ServerHTTP := TSQLHttpServer.Create('7979', [ServerDB], '+', useHttpApiRegisteringURI);
  ServerHTTP.AccessControlAllowOrigin := '*'; // allow cross-site AJAX queries
end;

// constructor TPhoMessartCommandFactory looks like
constructor TPhoMessartCommandFactory.Create(ARest: TSQLRest; AOwner: TDDDRepositoryRestManager = nil);
begin
  inherited Create(IPhoMessartCommand, TPhoMessartCommand, TMessart, aRest, TPhoMessart, aOwner);
  AddFilterOrValidate(['*'], TSynFilterTrim.Create);
  AddFilterOrValidate(['Name'], TSynValidateNonVoidText.Create);
end;

On the client side I have the following code:

var
  Model: TSQLModel;
  Client: TSQLHttpClient;
  MessartCommand: IPhoMessartCommand;
begin
  Model := TSQLModel.Create([]);
  Client := TSQLHttpClient.Create('localhost','7979', lModel);

  Client.ServiceDefine([IPhoMessartCommand], sicShared);
  Client.Services.Resolve(IPhoMessartCommand, MessartCommand);

  if not Assigned(MessartCommand) then
    raise Exception.Create('Can''t get PhoMessartCommand')
  else
    MessartCommand.SelectByName('somemessart');
end;

and if I call MessartCommand.SelectByName('somemessart'), I am getting this access violation because of Factory is nil.

Is it a bug or am I doing something wrong?

Thx for your help!

Offline

#23 2015-06-17 06:54:40

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,659
Website

Re: interface inheritance at RegisterInterfaces internal error L2111

Please use the debugger on the server side to find out why the factory is not resolved in your case.

You have to explicitly resolve the Factory reference, before using it.
You did not show this in your code.

Online

#24 2015-06-17 07:34:22

cypriotcalm
Member
Registered: 2015-02-18
Posts: 122

Re: interface inheritance at RegisterInterfaces internal error L2111

ab wrote:

Please use the debugger on the server side to find out why the factory is not resolved in your case.

I have debugged this code:

  ServerDB.Services.Resolve(IPhoMessartCommand, MessartCommand);

Everything seems to be ok. And I am getting true if the code below is executed:

function TInterfaceResolverInjected.Resolve(aInterface: PTypeInfo; out Obj): boolean;
begin
  if self=nil then
    result := false else
    result := TryResolve(aInterface,Obj);
end;

function TInterfaceResolverInjected.Resolve(const aGUID: TGUID; out Obj): boolean;
var known: TInterfaceFactory;
begin
  if self=nil then
    result := false else begin
    known := TInterfaceFactory.Get(aGUID);
    if known<>nil then
      result := Resolve(known.fInterfaceTypeInfo,Obj) else
      result := false;
  end;
end;

But I don't understand where the instance of the class TDDDRepositoryRestQuery is created.
The debugger doesn't call this code:

constructor TDDDRepositoryRestQuery.Create(aFactory: TDDDRepositoryRestFactory);
begin
  fFactory := aFactory;
  fCurrentORMInstance := fFactory.Table.Create;
end;

Do you have any idea?

Offline

#25 2015-06-17 07:35:22

cypriotcalm
Member
Registered: 2015-02-18
Posts: 122

Re: interface inheritance at RegisterInterfaces internal error L2111

ab wrote:

Please use the debugger on the server side to find out why the factory is not resolved in your case.

You have to explicitly resolve the Factory reference, before using it.
You did not show this in your code.

Also on the client side?
How and where can I do this? Code you give me a short code example of it?

Last edited by cypriotcalm (2015-06-17 07:38:03)

Offline

#26 2015-06-17 08:45:40

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,659
Website

Re: interface inheritance at RegisterInterfaces internal error L2111

The client side has nothing to do with the factory.
The factory is an implementation detail of TDDDRepositoryRestQuery, which stay on the server side.

I'll look further and come back.

Online

#27 2015-06-17 08:54:01

cypriotcalm
Member
Registered: 2015-02-18
Posts: 122

Re: interface inheritance at RegisterInterfaces internal error L2111

ab wrote:

The client side has nothing to do with the factory.
The factory is an implementation detail of TDDDRepositoryRestQuery, which stay on the server side.

I have thought the same smile

Is the reference to the factory not done with the followiing code?

  ServerDB.ServiceContainer.InjectResolver([TPhoMessartCommandFactory.Create(ServerDB)], True);
ab wrote:

I'll look further and come back.

Ok, thx, I'll wait

Offline

#28 2015-06-17 13:19:17

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,659
Website

Re: interface inheritance at RegisterInterfaces internal error L2111

This automatic injection is tested by TInfraRepoUserFactory.RegressionTests, as defined in dddInfraRepoUser.
Up to now, only direct call from the server side was made.
I've enhanced the tests to use a client/server connection (as you do).
There was indeed an issue, which has been fixed by http://synopse.info/fossil/info/ff269c01b1

But IMHO your code has still a problem: you define your IPhoMessartCommand service as sicShared.
A CQRS service is NOT meant to be defined as sicShared.
A CQRS service should have the client life-time, so should be defined as sicClientDriven.

Online

#29 2015-06-18 05:55:49

cypriotcalm
Member
Registered: 2015-02-18
Posts: 122

Re: interface inheritance at RegisterInterfaces internal error L2111

ab wrote:

This automatic injection is tested by TInfraRepoUserFactory.RegressionTests, as defined in dddInfraRepoUser.
Up to now, only direct call from the server side was made.
I've enhanced the tests to use a client/server connection (as you do).
There was indeed an issue, which has been fixed by http://synopse.info/fossil/info/ff269c01b1

I have just downloaded the nightly build and tried it out. I am still getting the same error. The "factory" field is nil when the framework is calling the function TDDDRepositoryRestQuery.ORMSelectOne.

By debugging I have noticed that the instance of PhoMessartCommand is resolved but the "factory" field is not set. See the code below:

function TDDDRepositoryRestQuery.ORMSelectOne(ORMWhereClauseFmt: PUTF8Char;
   const Bounds: array of const; ForcedBadRequest: boolean): TCQRSResult;
begin
  CqrsBeginMethod(qaSelect,result);
  if ForcedBadRequest then
    CqrsSetResult(cqrsBadRequest) else
    CqrsSetResultSuccessIf(Factory.Rest.Retrieve(ORMWhereClauseFmt,[],Bounds,
      fCurrentORMInstance),cqrsNotFound);
end;
ab wrote:

But IMHO your code has still a problem: you define your IPhoMessartCommand service as sicShared.
A CQRS service is NOT meant to be defined as sicShared.
A CQRS service should have the client life-time, so should be defined as sicClientDriven.

Thx for the advice! I have changed it.

Last edited by cypriotcalm (2015-06-18 06:22:59)

Offline

#30 2015-06-18 06:21:07

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,659
Website

Re: interface inheritance at RegisterInterfaces internal error L2111

There should still be something wrong in your code.
How is your TPhoMessartCommand class defined?

Please check the TInfraRepoUserFactory.RegressionTests, as defined in dddInfraRepoUser.

  TInfraRepoUser = class(TDDDRepositoryRestCommand,IDomUserCommand,IDomUserQuery)
  ...


  RestServer := TSQLRestServerFullMemory.CreateWithOwnModel([TSQLRecordUser]);
  try // then try from a client-server process
    RestServer.ServiceContainer.InjectResolver([TInfraRepoUserFactory.Create(RestServer)],true);
    RestServer.ServiceDefine(TInfraRepoUser,[IDomUserCommand,IDomUserQuery],sicClientDriven);
    test.Check(RestServer.ExportServer);
    RestClient := TSQLRestClientURIDll.Create(TSQLModel.Create(RestServer.Model),@URIRequest);
    try
      RestClient.Model.Owner := RestClient;
      RestClient.ServiceDefine([IDomUserCommand],sicClientDriven);
      TestOne(RestServer);
      RestServer.DropDatabase;
      USEFASTMM4ALLOC := true; // for slightly faster process
      TestOne(RestClient);
    finally
      RestClient.Free;
    end;
  finally
    RestServer.Free;
  end;

Using the debugger, you would be able to find out how it works, even on client/server.

Online

#31 2015-06-18 06:50:59

cypriotcalm
Member
Registered: 2015-02-18
Posts: 122

Re: interface inheritance at RegisterInterfaces internal error L2111

ab wrote:

There should still be something wrong in your code.
How is your TPhoMessartCommand class defined?

Arnaud, you are right! smile This time it's my mistake wink

I have defined this class in the same way your documentation requires it.
The point is that I have to inject the resolver before defining the service when initializing the server instance. Otherwise, the "factory" field is not set and I get an violation error.
But on the client side I have to do it vice versa, i.e. I have to define first the service and then to resolve the interface.

  // server side
  (...)
  ServerDB.ServiceContainer.InjectResolver([TPhoMessartCommandFactory.Create(ServerDB)], True);
  ServerDB.ServiceDefine(TPhoMessartCommand, [IPhoMessartCommand], sicClientDriven);
  (...)

  // client side
  (...)
  Model := TSQLModel.Create([]);
  Client := TSQLHttpClient.Create('localhost','7979', FModel);
  
  Client.ServiceDefine([IPhoMessartCommand], sicClientDriven);
  Client.Services.Resolve(IPhoMessartCommand, MessartCommand);
  (...)
ab wrote:

Using the debugger, you would be able to find out how it works, even on client/server.

I am using the debugger all the time! ;-)


But now it works and I continue to discover the amazing framework! A big thank you for your help and fast fixing the issues! smile

Last edited by cypriotcalm (2015-06-18 06:52:37)

Offline

#32 2015-06-18 09:01:19

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,659
Website

Re: interface inheritance at RegisterInterfaces internal error L2111

I've just updated the documentation to be more clear.

Thanks for the feedback.

Online

Board footer

Powered by FluxBB