From magazine topic to project implementation
Relevant service and technical pages for this post
In many IT departments the starting point is similar: a stable, process-close Delphi desktop application supports critical workflows, while new requirements push toward the web, portals, mobile use and integration with cloud services. At the same time C# is established in many companies when it comes to services, web APIs and identity integration. The central question is therefore no longer „Delphi or C#?“, but: C# and Delphi in a common architecture combined so that operation, maintenance, data management and security remain controllable.
This article describes practical architectural principles that prove themselves in enterprise environments where not everything can or should be rebuilt. The focus is on clear responsibilities between desktop client, services, data and interfaces – and on how to plan modernization steps with low risk, without jeopardizing ongoing processes.
Why mixed stacks are normal in enterprises
Evolved digital enterprise solutions rarely start from a greenfield. Delphi applications have often been extended over many years, close to business processes, with extensive data logic and deep know-how on special cases. In parallel, new requirements have emerged: self-service portals, automated data exchanges, integration of DMS/CRM/ERP, multi-tenancy, stronger auditability or single sign-on.
C# often offers advantages in this context for web and service ecosystems: a broad hosting spectrum, standardized middleware, solid integration with identity providers and established patterns for web APIs. Delphi remains strong where high-performance Windows desktop clients, long-maintained VCL applications or specific multiplatform clients (e.g. via FMX) are required.
The mix is therefore not an „exception“, but a realistic response to investment protection and modernization pressure. What is crucial is that joint operation does not become a long-term maintenance burden.
Architectural principle: clear layers instead of language boundaries
When two languages come together, there is a strong temptation to organize separation along technology („All Delphi is legacy, all C# is new“). Technically that often works in the short term, but in the long run it leads to friction: duplicated business rules, unclear responsibilities and hard-to-reproduce errors.
What has proven itself instead is a domain-oriented layering, often realized as a Layer-3 architecture: Presentation (UI), Domain (business logic) and Infrastructure (data access, external systems). The point is less the textbook model than the concrete effect in daily operation: decisions about data, validations and workflows are made in one place and exposed via stable interfaces.
In a mixed architecture this means in practice: Delphi can continue to provide a UI component (or specific workflows), while C# services encapsulate a domain layer — or vice versa. The important thing is that the edge between layers is technically clean and testable.
C# and Delphi in a common architecture: three proven integration patterns
There is no single ‚right‘ way to integrate Delphi and C#. Good decisions are guided by operations, security requirements, latency, data volume and release cycles. In practice, three patterns have emerged.
1) Service orientation over HTTP/REST as the standard integration
Often the most robust approach for operation and further development is coupling via REST-APIs (HTTP-based interfaces). Delphi clients call C# or Delphi services; C# portals use the same endpoints. This decoupling makes releases more predictable: a client update is not strictly necessary as long as the API remains backward compatible.
What matters is professional design: timeouts, retries, idempotence (repeatable requests without side effects), clear error codes and a versioning strategy. For administration and operations also count: consistent logs, traceable request IDs and well-measurable response times.
2) Shared database: only with clear rules
Shared database access by Delphi and C# can be tempting because it is initially fast. In the long run it is risky if both domains write directly to the same set of tables. The reason: business rules migrate into triggers, stored procedures or “somewhere in the client.” That complicates error analysis and audits.
If a shared database is unavoidable (e.g. during migration phases), clear rules help:
- Centralize write access: one system is the „system of record“ for specific entities.
- Define contracts: use views or APIs as a stable read layer instead of direct table access.
- Plan migration windows: always roll out database changes backwards-compatible (e.g. add new columns as optional first).
Technically, the database then becomes an infrastructure component, not the integration bus.
3) Messaging/Events for asynchronous processes
For decoupled workflows (e.g. import runs, notifications, post-processing, interface jobs) an asynchronous model is sensible: one system publishes events, another processes them. That reduces direct dependencies and stabilizes peak loads.
For IT management and admins the important points are: monitoring (queue lengths), dead-letter concepts (failed messages), restart behavior and clear business-level idempotence. Events are no substitute for clean master data management, but they are a useful tool for robust process chains.
Data contracts and compatibility: the often underestimated core
Regardless of the integration pattern, the quality of data contracts determines stability. A data contract is the binding description of fields, types, required/optional and semantics. In REST-APIs this is typically JSON; the important factor is not „JSON per se“ but the discipline in handling changes.
Proven rules that noticeably simplify operations:
- Extend rather than break: add new fields, continue to provide old ones initially.
- Document field semantics: not just „string“, but e.g. ISO date, time zone, permitted states.
- Treat enum values tolerant: clients must survive unknown values (forward compatibility).
- Use API versioning consciously: not every release requires a new version; but breaking changes must be clearly encapsulated.
These points are especially important when Delphi desktop clients cannot be updated as frequently as web services.
Authentication and authorization: a shared security model
Mixed architectures rarely fail because of „technology“; more often they fail due to inconsistent security. For companies the questions are: Who is allowed to do what? How is that verified? How is it audited? A common model avoids duplicate user management and contradictory roles.
In practice this leads to a central identity layer: for example via SAML 2.0 (federated single sign-on, common in enterprise environments) or OpenID Connect (OAuth2-based, often for modern Web APIs). C#-services can usually be connected directly to an identity provider; Delphi clients can obtain tokens and send them with API calls. It is important that desktop applications do not receive „special privileges“ via direct database access.
Central for admins:
- Token lifetimes and refresh strategy (so clients run stably and still remain secure)
- Service-to-Service Auth for internal communication (e.g. mTLS or signed tokens)
- Least Privilege: avoid overly coarse roles and permissions
- Audit logs: log security-relevant actions in a traceable way
Operational concepts: Windows- and Linux-services, IIS and processes in daily operations
An architecture is only „good“ in an enterprise if it is operable: updates schedulable, faults localizable, load manageable. In mixed landscapes the most common operational variants are:
- Windows- and Linux-services: suitable for background jobs, interface runs, workers; well integrable into classic Windows server operation models.
- Windows- and Linux-services/Daemon: sensible for containerized or VM-based operation models; often stable in long-running operation, good automation via systemd.
- Microsoft IIS: established hosting for Web applications and reverse-proxy scenarios in Windows-centric environments.
It is important that Delphi- and C#-components meet similar operational standards: consistent health endpoints (liveness probes), defined timeouts, bounded resource usage, and a clear deployment and rollback procedure. That reduces „technology-specific“ special treatments.
Logging, tracing and metrics: a shared observability level
Especially with two technology stacks, end-to-end diagnostic chains are crucial. A typical problem: the Delphi client reports „Fehler beim Speichern“, the C# service has a timeout, the database reports locks – without a common context.
Practices that have proven effective:
- Correlation IDs per request (Client → API → DB), so logs can be correlated.
- Structured logging (key/value instead of plain text lines), to allow filtering later.
- Metrics for latency, error rates, queue lengths and resource usage.
- Error classification: business errors (validation) separated from technical errors (timeout, network).
These fundamentals save more time in practice than any discussion about “the right language”.
Data access and migration: BDE-replacement, FireDAC and modern databases
In Delphi inventories, data access has historically played a major role. Where old access paths such as the Borland Database Engine (BDE) are still in use, additional pressure arises: operating system updates, 64‑bit transitions, driver availability, security requirements. A BDE-replacement then becomes not just modernization, but risk reduction.
Typical is the move to a BDE-replacement with native connectivity (modern data access layer in Delphi), combined with a database that is operationally manageable (e.g. PostgreSQL, SQL Server, MariaDB). For a joint Delphi/C# architecture, two aspects are important:
- Transaction boundaries: who starts/commits transactions, and how are concurrent write accesses governed?
- Locking and isolation strategy: so that desktop workflows and services do not block each other.
In migrations, a staged plan proves effective: first modernize the driver and access layer, then consolidate the data model, and subsequently stabilize integration interfaces. This makes error sources isolatable and rollbacks realistic.
Release management: reconciling different update cycles
A recurring source of tension is update frequency: web services can be rolled out more frequently, desktop clients often less so (rollout windows, user communication, packaging). A common architecture must take this asymmetry into account.
Practical consequences:
- API backward compatibility is mandatory, not optional.
- Feature flags (functional switches) help to enable new features server-side in a controlled manner.
- Schema migrations must run in phases: extend the database first, then have services use it, then update the client.
- Clear deprecation: remove old endpoints or fields only after a defined period.
Especially in regulated environments it is important to fix these rules in writing as architectural guardrails so that decisions are not reinvented on a per-project basis.
Typical pitfalls and how to avoid them systematically
From an operational standpoint, the most common problems in mixed Delphi/C# landscapes are predictable. If they are addressed early, long-term costs decline noticeably.
Pitfall 1: duplicated business logic
If a Delphi client and a C# service implement the same rules differently, “ghost errors” arise: a process works in the UI but fails during API import. Countermeasure: centralize rules in the domain layer (service) or assign them clearly by responsibility, including unambiguous validation responses.
Pitfall 2: UI workarounds instead of clean interfaces
“Quickly writing another database field” may seem harmless in individual cases, but it creates shadow interfaces without logging, authentication, or versioning. Better: consistently go through defined endpoints, even if that initially requires more discipline.
Pitfall 3: unclear responsibilities in operations
If it is not clear which team is responsible for which service, which log and which operating parameters, troubleshooting ends up as a game of ping-pong. Practically, a service map (which service, which dependencies, which ports, which internal SLAs) and standardized runbooks for common incidents help.
Pitfall 4: inconsistent security
A portal with SSO but a desktop client using local admin accounts is a problem in many audits. A common identity and role model reduces risk and support overhead.
Decision aid: What stays in Delphi, what goes into C#?
The sensible division depends less on ideology and more on process proximity and operational requirements. As guidance from an architecture and operations perspective:
- Delphi is often appropriate for: existing Windows desktop clients (VCL), very latency-sensitive UI workflows, offline-capable scenarios, long-term maintenance of established user interfaces.
- C# is often appropriate for: central REST APIs, integration services to ERP/DMS/CRM, identity-related components, portals and backend processes with a high rate of change.
- Decide consciously: data logic and validation should not be embedded „in the client“ when multiple frontends exist (desktop, portal, import jobs).
Important: the goal is not „everything into C#“, but a robust overall architecture in which modernization steps are plannable and business processes remain stable.
Modernization path: stepwise from application to system
In practice a shared architecture is often a transition, and a long one. A realistic modernization path avoids large-risk programs and focuses on measurable intermediate goals:
- Stabilize interfaces: introduce the REST API as the functional boundary, even if not everything inside is yet „neat“.
- Modernize data access: BDE-replacement, drivers, 64‑bit capability, clear transactions.
- Centralize identity: SSO and a role-based model for all access paths.
- Unify operations: logging/monitoring/health, clear deployments, reproducible environments.
- Decouple functional modules: move particularly change-prone parts into services, gradually streamline the UI.
This order is not dogmatic, but it typically minimizes dependencies: without stable interfaces and an operations concept, every further change becomes more expensive.
Conclusion: integration is an architectural task, not a question of languages
A viable combination of Delphi and C# is not created by „bridge libraries“, but by clear functional boundaries, clean data contracts and an operations concept that takes monitoring, security and release management seriously. When C# and Delphi deliberately interact within a shared architecture along lines of responsibility, companies gain primarily one thing: modernization without process disruption. Delphi can continue to reliably support stable desktop workflows, while C# services provide integration, web APIs and portals as central platform functions.
If you want to gradually modernize an existing Delphi landscape or cleanly connect C# services, an architecture review focused on interfaces, data, operations and security is the fastest route to sound decisions. More on this in direct discussion:
In the functional context, Delphi Modernization and REST-API for existing software also play an important role when integrations, data flows and ongoing development must interoperate cleanly.
Discuss a project or modernization initiative with Net-Base.
Next step
When the topic becomes an actual project, architecture, existing systems and operations should be considered together from the outset.
We support not only with individual issues, but also when source snippets, legacy topics, or portal ideas are to be turned into a robust enterprise project.
- Current state, target state and technical risks are assessed jointly.
- REST, data access, portals and rollout are not deferred to a later stage as secondary consequences.
- You can see early on which path is economically and operationally viable.