Migrating from RO/DA Delphi Server to Oxygene Net Core server. Second try

I have a very big server project, working fine in Delphi and plan to test how it will work on font net core, plus take advantage of others available platforms on net core.

I try in the past, and fail.

Why? because the only way to make it happen is sharing Delphi base code with net core. Theres no other chances it happens with a live project like this, to have to codebases or a lot of ifdef inside that codebase.

Im crazy? Is impossible to share codebase between Delphi and Oxygene? Maybe don’t. Maybe some simple adjustments in oxygene can do the big difference. I only knows is impractical to try this in the way the things are in this moment.

So, Im trying to do constructive suggestions to make easiest to taje that trip. I know many of that hit the
ideal scenario when working on oxygene language. Please consider that:

All the suggested adjustments are only for a full compatibility with Delphi and maybe not the ideal for the
Oxygene language daily usage. The point is , remember, make easiest share server code between Delphi and oxygene.

Let me explain that in detail.

Class aliases

We need class aliases to translate some Delphi classes (DA classes and RO classes, mostly) to dot net classes. See data modules ahead.

Units aliases

We also need units aliases to translate some Delphi units (DA classes and RO classes, mostly) to dot net classes. Remember : the idea is don’t touch Delphi code at all.

Units vs namespace.

Must I modify 2000 files , put an ifdef at the top to use the word namespace vs unit? Why not better in Delphi compatibility mode Oxygene recognizes that word and understand is another namespace? Every Delphi unit have a uses clauses referencing that namespaces. In Delphi compatibility mode is ideal allow to uses units as the first word in pascal unit.

Datamodules

Any Delphi servers have a lot of data modules. How to solve that with oxygene?
I think in a dfm to code automatic generator, and an initialization function (to put a name) called in the datamodule source file to generate all the classes needed, in case compiler is oxygene.

RTL

Stuff like freeandnil must be supported on Delphi compatibility unit on oxygene. I have no idea if that is supported right now. I believe you already do an impressive work there.

General usage of DA and RO

Must be analyzed how to accept code like this in DA dot net version.

var
  lConnection : IDAConnection;
  lQuery      : IDADataset;
  dw          : TDAWhereBuilder;
begin
  try
    lConnection := ServerDataModule.ConnectionManager.NewConnection(fDBConexion);
    if not lConnection.InTransaction then lConnection.BeginTransaction;
    lQuery        := SchemaGetDataset(lConnection, ServerDataModule.Schema, 'TABLA');
    dw            := lQuery.DynamicWhere;
    dw.Expression := dw.NewBinaryExpression('', 'IDTABLA',  dboEqual, 100);
    lQuery.Active := True;
    result  := lQuery.FieldByName('NAME').AsString;
    if lConnection.InTransaction then lConnection.CommitTransaction;
  except
    on e:exception do
    begin
      if lConnection.InTransaction then lConnection.RollbackTransaction;
      Log(' procedure X Error ' + e.Message)
    end;
  end;
end;

@antonk tell me in the past that code is very old fashioned. Maybe. I don’t know, but comparing the code in dot net you put… is fair more readable… And as it use interfaces is fair more simplest to release, by example, the connection.

In any case must be an equivalent way for each call to allow share the actual valid code in dot net.

Autogenerated RO DA intf files

AFAIK that is already compatible, must recheck how it works in my last try.

Delphi dpr file compatibility

A big plus, only RO team can evaluate if is possible.

I will adding to this list if something more comes to mi mind. But that items are the big stones to jump to start.

my .2 cents.

Best regards.

I guess you are referring to this thread: Migrating Data Abstract Delphi Server to .net console Server

The code sample in your post will leak DB connections in .NET
The rest is probable possible to implement by writing extension methods to emulate Delphi API
Also IDADataset type has no direct counterpart in .NET because Data Abstract for .NET uses native .NET DataTable and DataSet types instead

Yes, exactly.

Why? Theres no interface implemented in .NET?

I remember some time ago theres a working to unify DA and RO calls between platforms. Theres any progress on that or ETA?

I believe the rest of the stones have a medium difficult to jump, but that is the bigger and hard to solve without your collaboration.

Best regards.

Because you acquire connection from a ConnectionManager but never releases it back.
Btw it seems it will leak in Delphi as well if the Pooling is enabled for the ConnectionManager instance.
Not releasing precious resources like db connections will eventually result in issues with exhausted connection pool (either DA or internal database’s one) and/or memory leaks.

These are 2 completely different platforms with different approaches used. Even the naming conventions are different between Delphi and .NET

For the record, this was/is about unifying RO/DA APIs within Elements — ie have a common API for .NET, Cocoa, Java (and possibly extend to Island). Delphi is a completely separate codebase and there’s no easy way for the two to by synchronized (short of essentially writing a new RODA/Delphi from scratch and trying to match it closely to the Elements one — which I don’t see the demand for to justify the enormous effort — mostly, it would just annoy or put off our existing DA/Delphi users).

Your initial post in this thread does mention various options.suggestions for improving interoperability, both on the Oxygene and the RO/DA side, and those are worth looking into:

Those could be easily done, either by yourself or by us in a compatibility file, yes. simply define aliases you need in an Oxygene code file, eg

type
  ROBINBessage = public RemObjects.SDK.BinMessage;

etc and you should be set. Your bigger problem will be that even with the classes named the same, the classes won’t have the same methods and usage semantics, between the Delphi and .NET versions.

Again, you could create dummy namespace aliases so that the Delphi unit names in the uses clause can be “ignored”, because the names exist as namespace. eg

type
  MyDelphiUnit.Dymmy = public Object;

— now MyDelphiUnit exists as a namespace and can be in the uses clause.

We do have a DFM reader/parser as part of our Delphi VCL implementation, which is open source. Someone could leverage that to build a code conversion tool.

I believe we have FreeAndNil in Delphi RTL, but that won’t get you around the fact that Delphi and .NET use vastly different memory management systems, GC vs manual management.


Personally I think the best approach waked be to focus on getting non-plumbing code to be sharable easier — eg the code tat calls RO services, fetches DA data, and the Implementation files of RO Services. The actual RO/DA setup code (creating messages, services, data adapters, etc) would probably be best duplicated/translted — one copy for Delphi, one for .NET, while you migrate, while the “business” parts of your code could be shared between Delphi and .NET…

IMO that’s the best approach here: to move platform-specific code into different files while maintaining main business-logic shared among platforms.

We used a very similar approach in RO SDK and DA while porting them to different .NET platforms (at some moment there were like 10 different .NET platforms before they shrinked to only 3 modern .NET platforms). F.e. Windows Phone .NET and desktop .NET Framework had similar yet slightly different API. So we introduced a compatibility layer where differences were abstracted. This way the main codebase was shared between all platforms while platform-specific code was present localized only in a couple of code files

1 Like

Well, as is an interface. is supposed it release when stop being used (at the en do the procedure ) and library responsibility is release that connection! Can please @evgeny confirm if im wrong?

Sure, that apply excelente when you’re building libraries of pure code, but don’t fit as well when you build databases real word applications with intensive use of field access, updates, etc. Thats the problem here.

Objects (and Interfaces) get released when no longer referenced, but unmanaged resources on .NET only get disposed if you call Dispose() or use the using pattern. Else, the unmanaged resources an object holds (say, a database connection) will linger indeterministicly until the GC collects the data and calls the Finalizer, which might happen much later (or never).

I agree with your: on an ideal world, without deadlines, maybe. I love to write beauty code, believe me. And I love to have the time to rewrite 2 millions line of code. Maybe in another life. But returning to REAL life, I will love if you reconsider my proposals and consider make more easy the path from Delphi to Oxygene, including RO/DA users. Im sure many people will take the tour and start believe is possible if that things (really small changes IMHO) are considered and implemented. Until that happens is very impractical to use Oxygene for me. Even for new projects because I have a lot of own libraries and work baggage from almost 20 years in Delphi. Don’t plan to waste that work and start over from nothing in a near future.

Best regards.

Not big deal add a Dispose there. Is ok. regarding how it works on Delphi is @antonk right or wrong? I believe based on my own experience and server run, is wrong.

I think the code looks good. since lConnection is an interface, when it leaves the scope the object will be cleanly freed and released, which, for Delphi, will call Destroy and should free any non-memory resources the object holds, yes.

In .NET, the same pattern would not work. It’s a bit ironic I guess. Delphi has two extremes: Objects you need to ma sally free, interfaces get RC’ed and properly disposed. In .NET objects and interfaces are treated the same — they get automatically freed via GC as needed, but you need to Dispose() them explicitly (by direct all or with using) of they represent unmanaged resources.

I’m sorry, but I’m afraid your expectations are just unrealistic, for this. We’ll never have a scenario where you can have a complete, 100% code shared RO/DA server that compiles for both .NET and Delphi — not without a compete rewrite of RODA/Delphi to match .NET’s APIs or RODA/.NET to match Delphi’s, both of which are not feasible and — to be frank — we have zen literally zero demand our requests for, before this your’s.

We can and will continue to improve interoperability on the Oxygene level, to make more Delphi-style code compile with Oxygene (tomorrow’s build has a whole new batch of changes/improvements there). But on the RO/DA level, the best I can offer to you is to look at making Impl files and Into files API-compatible between the two — if that’s something that would be helpful, we can start looking into that, but if that’s not enough for you, than — frankly — it doesn’t right now make sense for us to bother with even that part, either (since no-one else has asked for it)…

I hope this makes sense.

Have sense. Maybe nothing ask for this before because: a) are happy with Delphi b) don’t have big projects needing to explore new horizons as I do. My Delphi project with RO/DA WAE, but I really need a real solution for ARM and Lazarus produce very unstable code. Im don’t trying to convince for anything, I start that topic only yo make a point about the actual state of things when you come from Delphi and try to get inside Oxygene. To my seems like a very high curve (in terms of code to change), and in was wrong thinking that can be solved for team RO easy.

I use some functions for high level call.

Some functions for open query and another functions for CRUD.

Can I send that to support and some on the team take a look? maybe that can be a start point, because adapting that function to work on NET will be a easy to make that work on Delphi and Oxygene.

Best regards.

IMHO, the way to die this would me to migrate, not to plan for long-term maintenance of a single code base for Delphi and .NET. As A ton suggested, share the business code (for now), but set up separate shell apps for the plumbing.setup that can host the same Impl files.

That way you can run tour Into code in the Delphi server and in he new .NET one, wile you finish the migration (eg wine its only half-way functional/ported on the .NET side)

Once everything is migrated, you can dump the Delphi plumbing host and just use the .NET server for everything.

In any case that’s how I would approach a migration like this.

Please, yes.

I understand. But for start a migration you need to be convinced. Is one way road. For sure you are full convinced of Oxygene and dot net. Maybe Delphi users don’t. So, AFAIK, with little changes I can run my server code on dot net. Seriously, I believe are small touches because is all pascal code and use of RO/DA some indy, and many Delphi RTL. Is a server code… all the business code is already alone. But what can id with some like that?

myData := lquery.Fieldbyname(‘afield’).asstring;

The easy way to share that code is do a similar call for dot net. Theres thousands of code like this so have sense just implement that and voila!

Will do today,

Thanks

Sure. that I8s* the kind of thing we could “easily” add a compatibility layer to DA/.NET for, so that DA/Delphi style code could work. What I’m thinking we could try:

Make compatible:

  • RO Service Implementations (probably just a matter of some aliases for attributes and base classes)
  • RO Service Imports (add a new CodeGen that emits an Intf for .NET, with a public API that matches Delphi’s Int files
  • a wrapper for .NET DataSet to look like a TDADataTable
  • w wrapper for .NET RemoteDataAdapter and LocalDataAdapter to look like Delphi one

(this would be in, say a RemObjects.DataAbstract.DelphiCompatibility.dll that adds extra helper/wrappers on top of RODA/.NET)

Not maske compatible:

  • core plumbing code (get the RO infrastructure booted & set ip messages, channels, connection manager, schema classes, etc.

(this code would be separate you port it to .NET, you don’t keep one code base that magically compiles for both, for these parts. Which, mind you, are the smaller part of a RO/DA app anyways).

How would that sound?

Sound very reasonable for me Marc, I really appreciate any effort the team can do on make short the bridge. :wink:

Best regards.

1 Like