#1 Re: mORMot 1 » Interfaced object being dumped from memory » 2017-08-25 10:25:46

No problem, Ab. Thanks for the quick response.

We're only using it to get access to our config file at this stage, which we don't want to reload and re-parse for every instance of our Interface-based service. As we're not in control of when the implementation is constructed, we can't use constructor based injection to pass the instance of the config file. How are you handling this scenario?

#2 Re: mORMot 1 » Interfaced object being dumped from memory » 2017-08-22 08:29:27

Hi Ab,

Sad to say it doesn't work when calling registerGlobal. Some more digging and looking at Stefan Glienke's advice, we followed the code and looking BeforeDestruction we came to the following conclusion:
In RegisterGlobal the code calls IInterface(aImplementation)._AddRef, but tries to free the implementation in FinalizeGlobalInterfaceResolution. This causes BeforeDestruction to raise an invalid pointer operation because the RefCount is not zero. Changing FinalizeGlobalInterfaceResolution's call from ImplementationInstance.Free to IInterface(ImplementationInstance)._Release, causes the issue to go away and no memory is leaked.

#3 Re: mORMot 1 » Interfaced object being dumped from memory » 2017-08-22 07:39:48

Thanks for the quick reply Ab. I am still curious as to why Delphi is exhibiting this behaviour. It's quite scary that it never called the destructor at all.

#4 mORMot 1 » Interfaced object being dumped from memory » 2017-08-21 14:36:17

willo
Replies: 6

Hi Ab,

We have a weird one. We're trying to use the DI feature where we inject an instance of a configuration reader to our service using ServiceContainer.RegisterGlobal and we ran across a very strange issue.

Sample code here (with all Synopse code removed to show a pure Delphi example):
https://stackoverflow.com/questions/457 … rom-memory

Anyone had to deal with something like this before?

#5 mORMot 1 » Stubbing a method that returns an interface » 2017-08-15 10:31:36

willo
Replies: 1

Hi guys,

We're trying to stub an interface that contains a method that returns an interface. Mormot complains with:
blah : blah parameter should be declared as const
when we try to register the interface.

Looking at the code mormot.pas(54472) we get:

      if Kind=mkFunction then
        with Args[n] do begin
          ParamName := @CONST_PSEUDO_RESULT_NAME;
          ValueDirection := smdResult;
          SetFromRTTI(PB);
        end;

This effectively asks the method to verify the result type as if it were a parameter. But the verification requires an Interface type to be const.

Is this a bug or by design?

#6 Re: mORMot 1 » Load/save TSQLRestBatch from/to file? » 2016-11-24 05:27:36

@hnb

 TSQLRestHelper = class helper for TSQLRest

is not Delphi 6/7 safe/

#7 mORMot 1 » CSV Parser ignoring blank fields » 2016-11-17 08:48:14

willo
Replies: 0

Hi AB,

When we recently required a CSV parser, I remembered that mORMot offered such a feature. We plugged in the CSVToRawUTF8DynArray function, but immediately started receiving issues. Some debugging revealed that blank field were ignored and investigating the code we saw:

procedure CSVToRawUTF8DynArray(CSV: PUTF8Char; var Result: TRawUTF8DynArray; Sep: AnsiChar = ',');
var s: RawUTF8;
begin
  while CSV<>nil do begin
    s := GetNextItem(CSV,Sep);
    if s<>'' then begin
      SetLength(Result,length(Result)+1);
      Result[high(Result)] := s;
    end;
  end;
end;

The line:

    if s<>'' then begin

seems like a bug to us, but I'm pretty sure you had some use case where you needed to ignore blank fields. This is, however, not part of the CSV standard (as much as CSV is a standard). Is there an alternative function to call or can we submit a fix?

#8 Re: mORMot 1 » Calling mORMot webservice from Java » 2016-10-04 14:47:27

Dexter,

I've never tried using it like that. From our use cases it's always been RESTfull, so the method to call is encoded in the URI, while the paramters are either POSTed or encoded as GET parameters (.../calculator/add?n1=1&n2=2)

Hope this helps

#11 Re: mORMot 1 » DTO implementing interfaces » 2016-04-05 13:00:19

Let me explain it like this:

type
  IDescribable = interface
     function getID : integer;
     function getDescription : RawUTF8;
  end;

  TPerson = class(TSynPersistent, IDescribable)
  private
     fID : integer;
     LastName: RawUTF8;
     FirstName: RawUTF8;
  protected
     function getID : integer;
     function getDescription : RawUTF8;
  published
     property ID : integer read fID write fID;
     property FirstName : RawUTF8 read fFirstName write fFirstName;
     property LastName : RawUTF8 read fLastName write fLastName;
  end;

Then on my client side I can have a library function:

procedure populateList( aStrings :  TStrings; aData : array of IDescribable )
var I : integer;
begin
  for I := low( aData ) to high(aData) do begin
    aStrings.AddObject( aData[i].getDescription, aData[i] );
  end;
end;

and call it like this:

var
  UserNames : TPersonDynArray;
begin
  SomeServiceINterface.GetLookupValues( aSomeLookups );
  populateList( cbUserDropDown.Items, aSomeLookups );
..

Please note - this is just from the top of my head to trying and explain what I'm trying to do.

#12 Re: mORMot 1 » DTO implementing interfaces » 2016-04-05 12:30:32

Hi AB,

Sure - but we have a function to populate a drop down, for instance. It would be great to pass the array of DTO's directly to it and by using an interface it could extract the correct description to use.

#13 mORMot 1 » DTO implementing interfaces » 2016-04-05 10:23:26

willo
Replies: 5

Hi AB,

We're sitting with a situation where we'd like out DTO's to implement certain interfaces. I realize that we should not inherited from TSynPersistent, in these cases, but where do you suggest we inherit from then?

#14 Re: Free Pascal Compiler » mORMot and FPC 3.0/3.1.1 » 2016-03-04 11:11:02

Hi guys,

Been looking at FPC / Lazarus lately, even if it's just server side for now. Lazarus is looking GOOD, and the new FPC features looks awesome. What a downer when I found this thread!

@Ab
1. Which of these changes have been implemented?
2. I notices the SAD(#25.4.4) encourages us to use FPC 3.1.1, but using the ComputeFPCInterfacesUnit function.
Are these still options or is 3.1.1 completely broken?

#15 Re: mORMot 1 » contnrs not supported for native mobile » 2015-10-16 12:07:23

Hi Ab,

An example that illustrate the issue is here: https://goo.gl/YEGyj7

#16 Re: mORMot 1 » contnrs not supported for native mobile » 2015-10-16 06:16:13

No. I'll try and put together a small test application to illustrate the behavior.

#17 Re: mORMot 1 » contnrs not supported for native mobile » 2015-10-15 12:59:34

Ab,

I had some time to play with it now, and it seems that the wrappers are not generating for my DTOs. I can't use the DTO unit, as my DTO's descend from SynCommons' TSynPersistent, and make heavy use of UTF8Raw.
Do I need to register my DTOs somewhere?

#18 mORMot 1 » Database reconnect on connection error » 2015-10-13 15:05:53

willo
Replies: 1

Hi Ab,

We've gone live with our first Rest server and lo and behold the TI team bounced the database server without restarting the REST server. This caused some very strange connections issues as the connections previously instantiated returned errorsm, but new ones worked - it took us a while to figure out what happened!

Researching possible solutions I found http://synopse.info/fossil/info/f024266c0839

I understand the ConnectionTimeOutMinutes property, which is something we'll investigate.

I am wondering about the proposed usage of ExceptionIsAboutConnection, though. How do you for see it being used?

Kind regards,

Willo

#19 Re: mORMot 1 » contnrs not supported for native mobile » 2015-10-03 13:35:10

Oh! I didn't realise that this applies to FMX clients. Thanks Ab!

#20 Re: mORMot 1 » contnrs not supported for native mobile » 2015-10-02 14:30:20

I can't seem to find anything relating to Interface based services (specifically TSQLHttpClient or other class that implements ServiceDefine) in any of the cross-platform dedicated units. Is this a Work In Progress?

#22 mORMot 1 » contnrs not supported for native mobile » 2015-10-02 13:23:36

willo
Replies: 9

Hi Ab,

Playing with Delphi 10 Seattle, I wanted to bring in mORMot, but quickly realised that there's a big issue. System.Contnrs is not supported in mobile projects! That means no TObjectList. 
See mobile white paper:

"Use the generic container classes defined in the unit Generics.Collections. The old-style Contnrs unit is not available on the mobile platform, because it is based on a pointer list (the non-generic TList class) and won’t work properly with the ARC memory management model."

Does that mean no mORMot for mobile projects, or is there a clever work around?

#23 Re: mORMot 1 » Linux ssl » 2015-08-26 06:43:03

Ab,

Is the FastCGI interface stable?

#24 Re: mORMot 1 » mORMot session recovery » 2015-08-21 09:16:04

Hi Ab,

Yes, I am using that. The issue came in with session recovery. Currently mORMot only tries TSQLRestServerAuthenticationSSPI (if SSPIAUTH is defined ) or TSQLRestServerAuthenticationDefault on the client side. I added a new event OnClientSetUser, which would allow the Client Application to take control of how SetUser prioritizes authentication schemes. It also makes it easy to reliably add new schemes and one can do away with the initial [CustomAuthScheme].SetUser() call. There was also a small issue where TSQLRestServerAuthenticationHttpAbstract.ClientSessionSign that would keep on appending the Cookie: header.

The current hash I was referring to is the current legacy hash we need to integrate to. We're looking at upgrading that to an SHA based hashing system to allow us to take advantage of the other more secure and compatible authentication schemes.
For now we're stuck with basic HTTP Auth, sending a plain text password, so that we can calculate the database hash on the server.

My changes work now. How do you prefer I submit the changes for your approval and comment?

#25 Re: mORMot 1 » mORMot session recovery » 2015-08-21 06:23:23

Hi Ab,

Digging a bit further, it looks like it has to do with my custom hash. On top of that I'm also relying on HTTP Basic Auth, as the current hash can not be coded in JS without considerable effort. I'm making some changes I'd like to recommend be added to the base mORMot libraries, but will submit a full diff / pull request once I've stabilized the extension.

#26 mORMot 1 » mORMot session recovery » 2015-08-20 08:36:21

willo
Replies: 5

In our quest for ever more robust software, I'm wondering how mORMot deals with a server restart. My tests didn't have a very elegant result. The only solution I found was to recreate the client connection, which is a problem when the connection reference has been passed down through several layers. To my mind it would be ideal if TSQLHttpClient, or some parent, could try and re-establish it's session on receiving a 403.

#27 Re: mORMot 1 » TSQLDBConnection on xxx should be connected » 2015-08-11 08:10:56

Hi Michal,

We're using ZEOSDBO-7.1.4-stable, is 7.2 stable enough to upgrade to?

#28 mORMot 1 » TSQLDBConnection on xxx should be connected » 2015-08-11 07:47:01

willo
Replies: 3

When fiddling around with transaction handling in Firebird 1.5, using ZEOS, we ran in to an issue where the transaction was not committed and we had to force a commit.

Digging around I found:
fDbConnection.MainConnection.StartTransaction;

Which worked pretty well in the unit tests, but testing it in a service produced an exception:
TSQLDBConnection on xxx should be connected

Forcing the connection before calling StartTransaction resolves the issue, but I'm wondering why TSQLDBConnection behaves this way.

#29 Re: mORMot 1 » Automatically converting an Array of Object to a Dataset » 2015-07-29 07:57:56

Google is great!
big_smile
Found the MdDataPack that came with Mastering Delphi 7.

#30 mORMot 1 » Automatically converting an Array of Object to a Dataset » 2015-07-29 06:45:12

willo
Replies: 3

Hi guys,

It seems that all the tools are there, but has anyone tried doing something like this yet?

#32 Re: mORMot 1 » Implementing your own password hash » 2015-07-28 14:52:41

*bump*

Would it help if I submit a pull request?

#33 mORMot 1 » Gaining access to Session User from an Interface Implementation » 2015-07-27 14:50:24

willo
Replies: 0

Hi Ab,

We have several methods that would like to know who the user was that performed the action. This would be the authenticated session user. What is the best way to get hold of the session user from inside a service implementation?

#34 Re: mORMot 1 » Implementing your own password hash » 2015-07-27 13:59:56

Yay! Found the problem!

The issue is in TSQLRestServerAuthenticationHttpBasic.RetrieveSession

Ab, can you please change line mORMot.pas[44879]:

    with TSQLAuthUser.Create do

to:

    with Ctxt.Server.SQLAuthUserClass.Create do

#35 Re: mORMot 1 » Implementing your own password hash » 2015-07-27 13:02:08

Thanks esmondb, but I'm starting to think that Ab was right and I should abandon the Auth stuff in mORMot. The issue seems to be that when CreateMissingTables is called, it creates the dummy tables, with no/basic/default information in.
This has the side effect that Group information will always be Admin (when forced to ID:1) and all the group information will always be default.

This doesn't play well with trying to force the Authentication credentials, as it keeps overriding group information from the in memory created group.

When I have more time to play, I'll see if it is possible to derive a new HTTP server that allows for a more flexible authentication/authorization model.

#36 Re: mORMot 1 » Implementing your own password hash » 2015-07-27 12:12:19

That was a good idea, but setting TSQLAuthGroup.SessionTimeout to 999999 has the same effect hmm

#37 Re: mORMot 1 » Implementing your own password hash » 2015-07-27 11:40:00

Hi Ab,

Yes, that's what I do:

type
  TDummySQLUser = class(TSQLAuthUser)
  protected
    procedure SetPasswordPlain(const Value: RawUTF8); override;
  public
    constructor Create( aUserName, aPassword : RawUTF8 ); reintroduce;
  end;
  TDummySQLGroup = class(TSQLAuthGroup)
  public
    constructor Create; reintroduce;
  end;

{ TDummySQLUser }

procedure TDummySQLUser.SetPasswordPlain(const Value: RawUTF8);
begin
  PasswordHashHexa := EncryptIBPass( Value );
end;

constructor TDummySQLUser.Create( aUserName, aPassword : RawUTF8 );
begin
  inherited Create;
  fID := 1;
  LogonName := aUserName;
  PasswordHashHexa := aPassword;
  GroupRights := TDummySQLGroup.Create();
end;

{ TDummySQLGroup }

constructor TDummySQLGroup.Create;
begin
  fID := 1;
  Ident := 'User';
end;

and then in my server class:

function TAbstractServer.RetrieveRevelightUser(
  Sender: TSQLRestServerAuthentication; Ctxt: TSQLRestServerURIContext;
  aUserID: TID; const aUserName: RawUTF8): TSQLAuthUser;
var
  Res : ISQLDBRows;
begin
  Result := nil;
  Res := fDbConnection.Execute(
    'select USER_ID, USER_PASSWORD '+
      'from USERS '+
     'where ACTIVE_FLAG=? and '+
           'USER_ID=UPPER(?)',
    [
      cACTIVEFLAG_ACTIVE,
      aUserName
    ]);
  if Res.Step then begin
    Result := TDummySQLUser.Create(Res['USER_ID'], Res['USER_PASSWORD']);
  end;
end;

Which works pretty well, as long as SetPasswordPlain is virtual.

I am experiencing some other issues too. From my test client it looks like my session is disappearing. From the logs I can see the Authentication attempt come through and succeed, but then the next call to [server]/[service]._contract_ I get a

{  "errorCode":403,  "errorText":"Forbidden"  }

response.

#38 mORMot 1 » Implementing your own password hash » 2015-07-27 10:51:57

willo
Replies: 10

Hi Ab,

I need to authenticate against an existing user database which calculates a proprietary hash. The easiest way I found to do that was to declare my own TSQLAuthUser. If we make TSQLAuthUser.SetPasswordPlain virtual, I can override the hash calculation and everything works.

Will you apply this to the code base?
    procedure SetPasswordPlain(const Value: RawUTF8); virtual;

I think this part of the library needs some work though, it's very tightly bound. Perhaps if one can abstract it out to use interfaces instead, that would make extending it really easy.

PS Article forthcoming.

#39 mORMot 1 » TOnAuthenticationUserRetrieve defintion » 2015-07-24 13:23:00

willo
Replies: 1

Hi Ab,

Shouldn't the definition of TOnAuthenticationUserRetrieve be of object, like so?

  TOnAuthenticationUserRetrieve = function(Sender: TSQLRestServerAuthentication;
    Ctxt: TSQLRestServerURIContext; aUserID: TID; const aUserName: RawUTF8): TSQLAuthUser of object;

#40 Re: mORMot 1 » Taming the Mormot » 2015-07-20 10:44:35

Thanks for your comments on my DI article, Ab. I fixed it up now.

#41 Re: mORMot 1 » Taming the Mormot » 2015-07-17 06:27:03

Thanks Ab, I'll probably go with a Git Pull request.

Next article is trying to uncover the mysteries of DI in mORMot. I might need some assistance in this regard, but will shout when I give up wink

#42 Re: mORMot 1 » Taming the Mormot » 2015-07-16 06:41:39

Ab,

I'm thinking I should take you up on your offer of publishing the sample projects in a dedicated folder under your "third party" source code tree. How would I go about doing that?

#43 Re: mORMot 1 » Taming the Mormot » 2015-07-15 11:27:30

I'm still exploring, so I reserve the right to retract anything I've published! big_smile I'm sure it won't get to that, but I AM sure I will want to revisit some of my earlier examples later, as I gain experience, to make adjustments.

#45 mORMot 1 » Taming the Mormot » 2015-07-14 13:51:21

willo
Replies: 15

Hi guys,

I've decided to blog my experiences and bits of knowledge I pick up as 'n explore the mORMot landscape here https://tamingthemormot.wordpress.com/ . Hopefully it will help someone else too. Comments welcome!

Willo

#46 mORMot 1 » Modeling the multi-legged Accounting Transaction pattern using ORM » 2015-06-18 08:08:57

willo
Replies: 0

Hi guys,

I've been wondering how to implement the multi-legged Accounting Transaction using the ORM as described by Fowler here: http://martinfowler.com/eaaDev/Accounti … ction.html

The ORM might not be the best tool to model this, but it would make for an interesting use case nonetheless.

What I have so far:

  TFinancialEvent = class;

  TTransaction = class( TSQLRecord )
  private
    fAmount: TCurrency;
    fAccount: TLegacyAccount;
    fTransactionDate: TDateTime;
    fStockEvent: TStockEvent;
  published
    property FinancialEvent : TFinancialEvent read fFinancialEvent write fFinancialEvent;
    property TransactionDate : TDateTime read fTransactionDate write fTransactionDate;
    property Account : TLegacyAccount read fAccount write fAccount;
    property Amount : TCurrency read fAmount write fAmount;
  end;

  TFinancialEvent = class( TSQLRecord )
  private
    fEventDate: TDateTime;
  published
    property EventDate : TDateTime read fEventDate;
  end;

Now, a lot of guys would now derive a new class from TFinancialEvent to handle specific events. Let's look at a Stock Procurement event, for instance:

  TStockProcurementEvent = class(TFinancialEvent)
  public
    constructor Create( aStockItem : TLegacyStockItem; aQuantity: Double; aAmount : TCurrency;
      aSupplier : TLegacySupplier; aReceivingLocation : TLegacyAccount; aDate : TDateTime ); reintroduce;
  end;

...

implementation

{ TStockProcurementEvent }

constructor TStockProcurementEvent.Create( aStockItem : TLegacyStockItem; aQuantity: Double; aAmount : TCurrency;
      aSupplier : TLegacySupplier; aReceivingLocation : TLegacyAccount; aDate : TDateTime );
var
  aTransaction : TTransaction;
begin
  inherited Create;
  fEventDate := aDate;

  //First add the Supplier leg
  aTransaction := Self.Add;
  aTransaction.Account := aSupplier;
  aTransaction.Amount := -aAmount;
  aTransaction.TransactionDate := aDate;

  //Then add the Receiver leg
  aTransaction := Self.Add;
  aTransaction.Account := aReceivingLocation;
  aTransaction.Amount := Amount;
  aTransaction.TransactionDate := aDate;
end;

There are some assumptions and the code is far from complete. The one solution I played with was to make TFinancialEvent a descendant from TCollection of TTransaction, which provides a clean separation from the Framework, but then there is no ORM involved.

So then I started playing with keeping a dynamic array of transactions in the Event object, but I haven't found an easy way to of adding or loading slave records using the ORM.

Any suggestions?

#47 Re: mORMot 1 » Serializing Enums as String » 2015-06-17 08:02:05

SOA using interface based services seem to be using TServiceMethodArgument.AddJSON specifically. Browsing through the code and these forums I noticed that it can encode Enums as String, if the soWriteHumanReadable option is set, but I can't seem to find a hook to customize the Options.

#48 mORMot 1 » Serializing Enums as String » 2015-06-15 08:28:10

willo
Replies: 2

Is there an easy way to have mORMot encode Enums as String? I see it's part of the standard serializer, but I can't seem to find a place to customize the serializer's options.

#50 Re: mORMot 1 » Serializing a Dynamic Array in Interfaced based services » 2015-06-11 15:37:59

Reducing and simplifying to:

function TSupplierQuery.GetSuppliers(const aCompanyID: RawUTF8; out Suppliers: TSupplierObjArray): TCQRSResult;
var
  Res : ISQLDBRows;
  Supplier : TSupplier;
begin
  Result := cqrsNotFound;
  Res := fDbConnection.Execute( 'select SUPPLIER_ID from SUPPLIERS where COMPANY_ID=?', [aCompanyID] );
  while Res.Step do begin
    Supplier := TSupplier.Create;
    GetSupplier(Res['SUPPLIER_ID'], Supplier);
    ObjArrayAdd( Suppliers, Supplier );
  end;
end;

Still produces an Access Violation.

Changing mORMot.pas[48685]:

          if IsObjArray then
            ObjArrayClear(Value^) else
            Wrapper.Clear;

to

          if false then//IsObjArray then
            ObjArrayClear(Value^) else
            Wrapper.Clear;

Works perfectly, but I'm pretty sure that will produce a memory leak.

Board footer

Powered by FluxBB