Guide de démarrage rapide
NTi est conçu pour répondre à une réalité que peu d'outils adressent : connecter votre IBM i à .NET et être opérationnel en moins de 15 minutes.
Aucun driver, aucun composant natif : NTi est un provider ADO.NET 100 % managé, distribué en simple package NuGet. Vous codez en C# avec une syntaxe familière, et l'API est réellement asynchrone de bout en bout : OpenAsync, exécution, lecture, fermeture, annulation au jeton de l'appelant.
NTi est entièrement multiplateforme : Windows, Linux et macOS, en x86, x64 ou ARM64. Côté serveur, il fonctionne de la V5R4 aux versions les plus récentes d'IBM i.
Simple, rapide et immédiat !
Prérequis
Côté développement
- Visual Studio 2022, JetBrains Rider, ou VS Code avec l'extension C#
- Une version .NET compatible :
- .NET 5 / 6 / 7 / 8 / 9 / 10
- .NET Framework 4.7.2 / 4.8 / 4.8.1
- .NET Standard 2.1 (.NET Core 3.x, Mono, Xamarin)
Côté IBM i
- IBM i V5R4 minimum, V7R4 ou ultérieure recommandée
- Les services TCP
*DATABASE,*RMTCMDet*SIGNONdémarrés - Une licence NTi active : Démarrer l'essai gratuit
💡 Pour le détail complet des prérequis et de l'installation de la licence, consultez la page Installation.
Étape 1 : Installer NTi via NuGet
Ouvrez un terminal dans votre dossier de projet et ajoutez les packages :
dotnet add package Aumerial.Data.Nti
dotnet add package Dapper
Ou via la console du Gestionnaire de packages Visual Studio :
Install-Package Aumerial.Data.Nti
Install-Package Dapper
💡 Pourquoi Dapper ? Dapper est un micro ORM léger qui mappe automatiquement les résultats SQL sur vos objets C#. Il enrichit votre connexion NTi de méthodes comme
Query<T>ouExecute, pour des interactions plus naturelles avec vos données IBM i.
Étape 2 : Ouvrir la connexion
OpenAsync est la voie normale : NTi est asynchrone de bout en bout, sans aucun sync-over-async. L'équivalent synchrone Open reste disponible.
using System;
using System.Data;
using Aumerial.Data.Nti;
using var conn = new NTiConnection("server=serverName;user=userName;password=password");
await conn.OpenAsync();
Console.WriteLine(conn.State == ConnectionState.Open
? "Connexion IBM i et licence NTi OK."
: "Connexion impossible.");
💡 Le pool de connexion est inactif par défaut. Pour une application web (ASP.NET Core, Blazor) ou toute charge concurrente, ajoutez
pooling=trueà la chaîne de connexion afin de réutiliser les connexions physiques au lieu de les rouvrir à chaque requête. Tous les mots-clés (pool, MFA, TLS, timeouts, bibliothèque par défaut) sont décrits dans la page Chaîne de connexion.
Étape 3 : Lire des données
Avec Dapper, QueryAsync<MyRecord> exécute le SELECT et mappe chaque ligne sur votre classe (correspondance colonne/propriété insensible à la casse). La version synchrone Query<MyRecord> existe aussi.
using System;
using System.Linq;
using Aumerial.Data.Nti;
using Dapper;
using var conn = new NTiConnection("server=serverName;user=userName;password=password");
await conn.OpenAsync();
var records = (await conn.QueryAsync("SELECT ID, LABEL FROM MYLIB.MYTABLE")).ToList();
foreach (var record in records)
Console.WriteLine($"{record.Id} : {record.Label}");
public class MyRecord
{
public string Id { get; set; }
public string Label { get; set; }
} Étape 4 : Écrire des données
using System;
using Aumerial.Data.Nti;
using Dapper;
using var conn = new NTiConnection("server=serverName;user=userName;password=password");
await conn.OpenAsync();
int rows = await conn.ExecuteAsync(
"UPDATE MYLIB.MYTABLE SET LABEL = @label WHERE ID = @id",
new { label = "Updated", id = "REC-001" });
Console.WriteLine($"{rows} ligne(s) mise(s) à jour.");
💡 Pour un exemple complet avec Entity Framework Core (Code First, DB First, CRUD), consultez le tutoriel CRUD avec EF Core.
Étape 5 : Exploiter toutes les ressources IBM i
NTi va bien au-delà du SQL : commandes CL avec ExecuteClCommand, appels de programmes RPG, COBOL ou CL avec CallProgram, procédures exportées des programmes de service avec CallServiceProgram, procédures stockées, le tout avec les variantes asynchrones correspondantes.
💡 Chaque connexion NTi pilote deux jobs serveur : le SQL s'exécute dans un job QZDASOINIT, les commandes et programmes dans un job QZRCSRVS. Leurs QTEMP et CURLIB sont donc séparées.
Exécuter une commande CL
using System;
using Aumerial.Data.Nti;
using var conn = new NTiConnection("server=serverName;user=userName;password=password");
await conn.OpenAsync();
try
{
await conn.ExecuteClCommandAsync("CRTLIB LIB(MYLIB) TEXT('My new library')");
}
catch (NTiCommandException ex)
{
// Pile de messages IBM i : identifiant et texte de chaque message
foreach (var message in ex.Messages)
Console.WriteLine($"{message.Id} : {message.Text}");
}
💡 Consultez le tutoriel Exécuter une commande CL.
Appeler un programme RPG
using System;
using System.Collections.Generic;
using Aumerial.Data.Nti;
using var conn = new NTiConnection("server=serverName;user=userName;password=password");
await conn.OpenAsync();
var parms = new List
{
new NTiProgramParameter("Hello", 10).AsInput(), // CHAR(10) en entrée
new NTiProgramParameter("", 128).AsOutput() // CHAR(128) en sortie
};
await conn.CallProgramAsync("MYLIB", "MYPGM", parms);
string result = parms[1].GetString(0, 128);
Console.WriteLine(result);
💡 Consultez le tutoriel Appeler un programme pour les paramètres typés (binaires, décimaux packés et zonés) et les récepteurs à taille variable.
Appeler une procédure d'un programme de service
CallServiceProgram appelle une procédure exportée d'un programme de service, via l'API système QZRUCLSP. Ici, la procédure C gethostname remplit un buffer fourni par l'appelant. Attention : le nom d'export est sensible à la casse.
using System;
using System.Collections.Generic;
using System.Data;
using Aumerial.Data.Nti;
using var conn = new NTiConnection("server=serverName;user=userName;password=password");
await conn.OpenAsync();
var buffer = new NTiProgramParameter(new byte[64], ParameterDirection.InputOutput);
var length = new NTiProgramParameter(64)
{
// BINARY(4) passé par valeur ; par référence est le défaut
ServiceProgramParameterFormat = NTiServiceProgramParameterFormat.ByValue
};
var rc = await conn.CallServiceProgramAsync(
"QSYS", "QSOSRV1", "gethostname",
new List { buffer, length },
NTiServiceProgramReturnFormat.Integer);
if (rc != null && rc.GetInt() == 0)
Console.WriteLine(buffer.GetString(0, 64).TrimEnd('\0', ' '));
💡 Consultez le tutoriel Appeler un programme de service pour les formats de paramètres, les retours Integer et IntegerAndErrno et la gestion des erreurs.
Appeler une procédure stockée
using System;
using System.Data;
using System.Linq;
using Aumerial.Data.Nti;
using Dapper;
using var conn = new NTiConnection("server=serverName;user=userName;password=password");
await conn.OpenAsync();
var parameters = new DynamicParameters();
parameters.Add("myParam", dbType: DbType.Decimal, direction: ParameterDirection.Output);
var records = (await conn.QueryAsync(
"MYLIB.MYPROC",
parameters,
commandType: CommandType.StoredProcedure)).ToList();
Console.WriteLine(parameters.Get("myParam"));
💡 Consultez le tutoriel Procédure stockée pour un exemple complet avec les approches DataReader et Dapper.
Et maintenant ?
Vous êtes opérationnel. Voici quelques pages pour aller plus loin :
- Chaîne de connexion : tous les mots-clés,
pooling=true, MFA, TLS, timeouts - Requêtes SQL : marqueurs
?et@name, Dapper, multi result sets - Appeler un programme de service : procédures exportées via QZRUCLSP