Migrer de NTi 4 vers NTi 5

La promesse

NTi 5 est une réécriture complète du provider : nouveau moteur de protocole, de conversion et de pooling, mais même API publique et mêmes mots-clés de chaîne de connexion que NTi 4. Une application NTi 4 recompile sans changement de code : la migration consiste à mettre à jour la référence de package.

dotnet add package Aumerial.Data.Nti --version 5.0.0

Les écarts délibérés avec la version 4 sont peu nombreux, listés ci-dessous, et chacun a un remède immédiat. Le reste de l'article détaille les défauts conservés, ce que la version 5 apporte, et la règle de versions du volet EF Core.

💡 Les packages 4.x sont dépréciés sur nuget.org, avec un message pointant vers la 5.0.0. Ils restent installables pour les applications gelées, mais les correctifs et les évolutions arrivent désormais en 5.x.


Plateformes et prérequis

Le package cible net472, netstandard2.1, net5.0, net8.0 et net10.0 : il se consomme depuis .NET Framework 4.7.2, 4.8 et 4.8.1 comme depuis .NET 5, 6, 7, 8, 9 et 10, pour tous les types de charge : console, ASP.NET Core et Blazor, WinForms et WPF, services Windows ou systemd, conteneurs, Azure Functions et AWS Lambda, MAUI (via net8.0 et plus).

NTi 5 est 100 % managé, sans dépendance native et sans recours à System.Text.Encoding.CodePages : l'assembly est AnyCPU et tourne sur toutes les architectures où .NET s'exécute : x86, x64 et ARM64 (Windows, Linux, macOS), et, avec .NET 8 et plus, ppc64le (Linux on Power) et s390x (Linux on IBM Z).

Côté serveur, IBM i V5R4 minimum pour tout le volet ADO.NET (SQL, commandes CL, appels de programme). V7R4 ou plus est recommandé ; seule réserve constatée sous V7R2 : certaines collections GetSchema s'appuient sur des catalogues QSYS2 récents. Le volet EF Core exige IBM i 7.2 ou plus.


Un écart, un remède

Chaque différence de comportement entre NTi 4 et NTi 5 est délibérée et se corrige en une ligne :

Écart Comportement en version 5 Remède
Mappings UDT NTiUDTMapping et SetUDTMappings sont retirés ; les types distincts sont lus sous leur type de base Supprimer les mappings ; convertir côté applicatif si nécessaire
Propriétés obsolètes UseDefaultPorts, RetreiveSuccessMessages, IgnoreNonQueryResult et PreFetch, déjà inertes en v4, sont retirées Supprimer les références ; ports fixes via signon port, database port et command port ; préchargement via fetch ahead
untrusted Défaut false : le certificat TLS du serveur est validé Déployer une chaîne de certificats de confiance ; untrusted=true réservé aux tests
Blocking factor Adaptatif par défaut : dimensionné sur la largeur des lignes pour viser block size blocking factor=1000 pour retrouver le dimensionnement fixe de la v4
AdditionalFactorCallback Obsolète : compile encore, avec avertissement AdditionalFactorProvider (contexte serveur et profil) ou AdditionalFactorAsyncProvider (jeton d'annulation), voir plus bas
Classes scellées Les classes principales sont sealed Remplacer l'héritage par la composition
Hiérarchie d'exceptions NTiException dérive désormais de DbException Aucun : catch (NTiException) continue de fonctionner, et les catch (DbException) génériques attrapent désormais aussi NTi
Savepoints Save, Rollback(name) et Release mal séquencés lèvent au lieu de ne rien faire Corriger l'ordre des appels
Double Open Open sur une connexion déjà ouverte lève, conformément au contrat ADO.NET Fermer avant de rouvrir, ou créer une nouvelle connexion
Mot de passe ConnectionString expurge le mot de passe une fois la connexion ouverte persist security info=true pour l'ancien comportement
Precision et Scale Suivent le contrat DbParameter standard : type byte Adapter les affectations int (cast ou littéral)
CCSID des paramètres Un NTiProgramParameter construit avec un ccsid explicite ne modifie plus l'encodage par défaut des autres paramètres du process Passer le ccsid sur chaque paramètre qui en a besoin
Valeurs invalides Une valeur invalide d'un mot-clé connu de la chaîne de connexion lève à l'affectation Corriger la valeur ; les mots-clés inconnus restent ignorés, compat v4

Les membres standard concernés suivent le contrat ADO.NET documenté par Microsoft : DbException et DbParameter.Precision.


MFA : remplacer AdditionalFactorCallback

En v4, AdditionalFactorCallback fournissait le facteur d'authentification additionnel sans contexte. En version 5, la propriété compile toujours (marquée obsolète), mais les fournisseurs contextuels la remplacent : AdditionalFactorProvider reçoit le serveur et le profil en cours d'authentification, et AdditionalFactorAsyncProvider reçoit en plus le jeton d'annulation de OpenAsync. Les deux peuvent être appelés plusieurs fois quand le pool ouvre des sessions physiques.

using System;
using Aumerial.Data.Nti;

using var connection = new NTiConnection("server=MYIBMI;user=MYUSER;password=MYPASSWORD;pooling=true");

// NTi 5 : le fournisseur reçoit le contexte d'authentification
connection.AdditionalFactorProvider = context =>
{
    Console.Write($"Code TOTP pour {context.User} sur {context.Host} : ");
    return Console.ReadLine();
};

await connection.OpenAsync();
Console.WriteLine("Connexion ouverte avec MFA.");

Un facteur statique reste possible via le mot-clé additional factor de la chaîne de connexion ou la propriété AdditionalFactor.


Les défauts conservés de la v4

Trois défauts historiques sont volontairement conservés pour ne pas changer le comportement des applications migrées :

  • Le pooling est inactif par défaut. Ajoutez pooling=true, fortement recommandé pour les charges web. NTiConnection.ClearPool(connection) et NTiConnection.ClearAllPools() purgent les pools ; l'identité client (application name, client accounting, client user identifier, client program identifier) fait partie de la clé de pool.
  • Tous les timeouts sont illimités par défaut (0 = infini) : fixez connect timeout et CommandTimeout selon votre contexte.
  • Les mots-clés inconnus de la chaîne de connexion sont ignorés : une chaîne v4 passe telle quelle.

Ce que la version 5 apporte

Sans changer votre code, la version 5 remplace tout le moteur :

  • Async réel de bout en bout : de OpenAsync à DisposeAsync, aucune I/O synchrone déguisée, annulation au jeton de l'appelant à chaque étape. Faites de l'async la voie normale dans vos services ; l'API synchrone reste complète. Nouveau : ExecuteClCommandAsync et CallProgramAsync.
  • Appels de procédures exportées de programmes de service : CallServiceProgram et CallServiceProgramAsync.
  • default ccsid : assertion du CCSID des colonnes non taguées (ateliers en QCCSID 65535).
  • fetch ahead : le bloc de lignes suivant est demandé pendant le décodage du bloc courant.
  • Conversions CCSID souveraines : 179 CCSID (EBCDIC simple octet, double octet et mixte SO/SI, Unicode, ASCII/OEM), tables extraites d'un IBM i et contre-vérifiées face à JTOpen et ICU.
  • Un skill pour agents IA embarqué dans le package (agents/SKILL.md) ; installation opt-in dans votre dépôt : dotnet msbuild -t:NTiInstallAgentSkills.

Vérifier la migration

Un test de fumée asynchrone suffit à valider le changement de version :

using System;
using Aumerial.Data.Nti;

using var connection = new NTiConnection("server=MYIBMI;user=MYUSER;password=MYPASSWORD;pooling=true");
await connection.OpenAsync();

using var command = connection.CreateCommand();
command.CommandText = "SELECT COUNT(*) FROM QSYS2.SYSTABLES WHERE TABLE_SCHEMA = @schema";
command.Parameters.Add(new NTiParameter { ParameterName = "@schema", Value = "QSYS2" });

var count = await command.ExecuteScalarAsync();
Console.WriteLine($"Tables cataloguées dans QSYS2 : {count}");

Le volet EF Core : la règle X.5.0

Le provider EF Core est publié dans les packages Aumerial.EntityFrameworkCore versionnés 8.5.0, 9.5.0 et 10.5.0 : la majeure suit votre version d'EF Core (8, 9 ou 10) et la mineure 5 indique la génération NTi du moteur sous-jacent. Choisissez le package aligné sur votre application : EF Core 8 → 8.5.0, EF Core 9 → 9.5.0, EF Core 10 → 10.5.0. Chaque package s'appuie sur Aumerial.Data.Nti 5, exige IBM i 7.2 ou plus et la convention de nommage sql. Le détail est couvert par le volet Entity Framework Core.


Et maintenant ?

Reconnexion au serveur...

La connexion au serveur a été perdue. La page va se recharger.