Overview
Introduction
NTi Data Provider is AUMERIAL's fully managed access provider for IBM i (AS/400, iSeries): it connects any .NET application to DB2 for i and to the system's native resources, with no ODBC driver, no OLE DB, no IBM i Access, and nothing to install on the client side:
- Synchronous and asynchronous SQL: strict ADO.NET implementation, with true asynchrony end to end (from
OpenAsynctoDisposeAsync) - CL commands: direct execution, with the server's message stack surfaced on error
- Program calls: RPG, CL, COBOL, and system APIs, with typed parameters
- Service programs: calling exported procedures through QZRUCLSP
- Entity Framework Core 8, 9, and 10: via the companion package
Aumerial.EntityFrameworkCore - MFA: additional authentication factor (IBM i TOTP), including asynchronously
- Connection pooling: a single, generic pool, with client identity included in the pool key
- TLS: encryption of the host servers, with certificate chain validation on by default
Note:
The programming model is one .NET developers already know: NTi implements the standard ADO.NET contract (see Microsoft's ADO.NET documentation), and this documentation focuses on what is specific to NTi and to IBM i.
Fully managed: everywhere .NET runs
NTi is written entirely in managed code, without the slightest native dependency, down to its text conversions: where most providers rely on System.Text.Encoding.CodePages to translate EBCDIC, NTi ships its own CCSID tables (EBCDIC, DBCS, Unicode), extracted from a real IBM i and cross-checked against reference implementations.
The assembly is AnyCPU: a single binary, no per-architecture variant, no native runtime to deploy. NTi therefore runs on every architecture where .NET runs:
- x86 and x64 (Windows, Linux, macOS)
- ARM64 (Windows, Linux, macOS, including AWS Graviton and Apple Silicon)
- ppc64le on .NET 8 or later (Linux on Power, including on the same machine as the IBM i)
- s390x on .NET 8 or later (Linux on IBM Z)
A Windows desktop client, a Linux container, an ARM64 serverless function, or a Linux on Power partition next to the IBM i: the same package runs everywhere, with no recompilation.
Architecture: host servers and two jobs per connection
NTi talks directly to the IBM i's host servers over TCP/IP or TLS, building the protocol's data streams itself, and never sends the password in clear text:
| Use | Host server | IBM i job |
|---|---|---|
| Signon (authentication, at connection open) | *SIGNON | QZSOSIGN |
| SQL (database) | *DATABASE | QZDASOINIT |
| CL commands and programs | *RMTCMD | QZRCSRVS |
The signon job only serves the opening of the connection, then disappears.
For the rest of its life, every open NTiConnection relies on two distinct IBM i jobs: one for SQL, one for CL commands and programs. That separation has an important consequence: the two jobs each have their own QTEMP and their own CURLIB. An object created in QTEMP by a CL command is not visible from SQL, and vice versa. To run CL inside the SQL job (and share its QTEMP), the SQL bridge CALL QSYS2.QCMDEXC('...') is still available, at the cost of going through the SQL engine. The connection's DatabaseJob and CommandJob properties let you identify both jobs at any time (tracing, WRKJOB, debugging).
The lifecycle is fully managed: every NTi connection owns its TCP sockets, and closing it (Close, Dispose, DisposeAsync) cleanly ends the associated IBM i jobs, unless the pool keeps them for reuse. No more "ghost" QZDASOINIT jobs piling up on the server. The transport always reads complete frames before parsing them: a parsing error never leaves a connection out of sync.
Default ports (8471, 8475, 8476, port mapper 449, TLS variants 94xx) are covered in Prerequisites.
The NTi packages
| Package | Version | Role |
|---|---|---|
Aumerial.Data.Nti |
5.0.0 | The ADO.NET provider, the subject of this documentation. An earlier generation remains available for existing applications, with an unchanged public contract: code already written keeps compiling and running as is. |
Aumerial.EntityFrameworkCore |
8.5.0 9.5.0 10.5.0 |
The Entity Framework Core provider. The major version tracks the EF Core version (8, 9, or 10); the minor version, 5, identifies the underlying NTi generation. |
Features
Database (SQL)
NTi implements the full ADO.NET model, connection, command, reader, parameters, and adapter included, with transactions and GetSchema metadata to match.
- True asynchrony: the async path performs no synchronous I/O, from
OpenAsync(pooling, TCP/TLS, signon, MFA included) through toDisposeAsync. Cancellation honors the caller's token everywhere; by contract, cancelling an in-flight operation breaks the connection (theOperationCanceledExceptioncarries the caller's token, and the connection has to be reopened). - Parameters: positional
?or named@namemarkers, never both in the same command. Dapper works without adaptation. - Stored procedures: input/output parameters and multi-result-set procedures, walked with
NextResult. - LOBs: BLOB, CLOB, DBCLOB, and XML, read directly or through locators (async path included).
- Transactions:
BeginTransaction(IsolationLevel)(ReadUncommitted through Serializable, ReadCommitted by default), savepoints viaSave/Rollback/Releaseand their async equivalents. IBM i commitment control assumes journaled tables:CREATE SCHEMAjournals automatically,CRTLIBdoes not. - Types: every DB2 for i type, including packed/zoned decimal, DECFLOAT, GRAPHIC, and FOR BIT DATA (returned as binary, never silently converted).
CL commands and program calls
Without going through SQL, on the dedicated QZRCSRVS job:
ExecuteClCommand/ExecuteClCommandAsync: runs any CL command. On failure,NTiCommandExceptionexposes the server's full message stack (ID, severity, text, help).CallProgram/CallProgramAsync: calls RPG, CL, or COBOL programs. Parameters are built withNTiProgramParameter, which offers typed constructors (CHAR with CCSID, BINARY(2)/BINARY(4), packed/zoned decimal, raw bytes, arrays) and lets you compose data structures through chainedAppendcalls. Reading the output buffer is typed as well, withGetString,GetInt,GetShort,GetPackedDecimal,GetZonedDecimal,GetBytes, orGetDTSTimestamp. An empty receiver (new NTiProgramParameter()) automatically resizes to the data actually written by the program, which makes it well suited to VARCHAR returns and to APIs with a variable-length receiver.- System APIs (QUSROBJD, QUSLOBJ, and so on) are called just like ordinary programs.
Service programs (QZRUCLSP)
CallServiceProgram / CallServiceProgramAsync call the exported procedures of service programs, through the QZRUCLSP system API:
- The export name is case-sensitive (interpreted in CCSID 37 by default, configurable).
- Parameters pass by reference (default) or by value (
ByValue, restricted to BINARY(4) values of exactly 4 bytes), with a maximum of 7 parameters. - The possible return values are
None,Integer, orIntegerAndErrno(value and errno read from the return parameter). A pointer return is not supported, since a server-side space pointer is meaningless on the client: procedures that produce text instead return it through a buffer supplied by the caller.
Entity Framework Core
The Aumerial.EntityFrameworkCore package supports EF Core 8, 9, and 10 (see the EF Core documentation):
- LINQ and idempotent migrations
ExecuteUpdate/ExecuteDelete- IDENTITY values read back through FINAL TABLE
- Optimistic concurrency via ROW CHANGE TIMESTAMP
- HiLo sequences
- Scaffolding of existing databases (zoned/packed decimal, FOR BIT DATA, DECFLOAT, keyless tables)
sql naming is required (naming=sql, NTi's default), and the EF Core layer requires IBM i 7.2 or later.
Security
- Signon: password never sent in clear text, every QPWDLVL level supported.
- TLS:
ssl=trueswitches the host servers to their TLS ports. The certificate chain is validated by default (untrusted=false), with validation disabled reserved for test environments. - MFA: an additional IBM i TOTP factor, supplied statically (
AdditionalFactor), through a delegate (AdditionalFactorProvider), or through an async delegate honoring the cancellation token (AdditionalFactorAsyncProvider).AdditionalFactorCallbackremains available as an older API kept for compatibility. - Connection string:
persist security info=falseby default; the password is stripped fromConnectionStringas soon as the connection opens.
Connection pooling
The pool is single and generic, off by default. Turn it on with pooling=true, which is strongly recommended for web and service workloads. The pool key never contains the password in clear text, and it includes the client identity (application name, client accounting, client user identifier, client program identifier), so two distinct identities never share a connection.
NTiConnection.ClearPool(connection) and NTiConnection.ClearAllPools() purge pools on demand.
Getting set up
On the .NET side, everything lives in the Aumerial.Data.Nti NuGet package: no installation, no software prerequisite beyond the .NET runtime.
On the IBM i side, you need valid credentials, the TCP host servers started, and a license key installed in the KNTI library (a free 30-day trial license is available at portal.aumerial.com).
What's next?
- Prerequisites: IBM i and .NET versions, architectures, network ports
- Installation: license, NuGet package, and your first program
- Quickstart guide: first connection and first IBM i calls
- Connection: connection string, pooling, MFA, TLS