Returning nested PODO from XData service

I have a simple service contract for authentication:

  [ServiceContract]
  IAuth = interface(IInvokable)
    ['{20BBDF2D-CA6B-4CCA-92DB-59A038EE2679}']
    function Login(const Email, Password: string): TLoginResult;
  end;

where TLoginResult is a PODO which contains within it another PODO.

  [JsonInclude(TInclusionMode.Always)]
  TLoginUser = class
  private
    Fname: string;
    Femail: string;
    Fid: string;
  public
    property id: string read Fid write Fid;
    property name: string read Fname write Fname;
    property email: string read Femail write Femail;
  end;

  [JsonInclude(TInclusionMode.Always)]
  TLoginResult = class
  private
    FUser: TLoginUser;
    FaccessToken: string;
  public
    constructor Create;
    destructor Destroy; override;
    property user: TLoginUser read FUser write FUser;
    property accessToken: string read FaccessToken write FaccessToken;
  end;

The constructor and destructor for TLoginResult just create and destroy the FUser object.

When I compile this into a (linux) apache module and call the API using PostMan, I get a message to say that it caused the server to return an unkown error 520 (!).

If I remove the user property, it works, but the web framework I use needs a separate user object to be returned (or lots of web code needs to be refactored).

From the manual, it looks like it should be possible to return a nested PODO like this, so I assume I am doing something daft...

Any suggestions for how to do this correctly?

  • Niels

So, if I remove the FUser.Free from the destructor, it no longer crashes.

Of course, that then raises the concern - am I now leaking memory? What is the proper way to ensure the memory for FUser is released?

XData destroys all objects serialized in the response. Thus, it will indeed destroy both TLoginResult instance and the TLoginUser instance, so you are fine.

If you want to keep the User lifetime to be managed by the TLoginResult object, you can set the following property in your Login implementation:

TXDataOperationContext.Current.Handler.ActionResultDestruction := TActionResultDestruction.RootOnly;

This way, only the root object (TLoginResult) will be destroyed, and it will be up to you (or the root object) to destroy other objects. This was also discussed here: access violation in simultaneous request of the same resource using service. - #3 by wlandgraf.