Stratégie du runtime C# au niveau ABI
Statut documentaire : architecture — voir Maturité et preuves.
Objectif
Cette page explique comment le binding .NET relie les wrappers C# générés au logiCells Runtime sans exposer les détails de packing de l'ABI au code applicatif.
Le modèle de programmation normal repose sur trois éléments :
- des classes .NET générées ;
IClientRuntimecomme contrat d'exécution ;- une implémentation locale ou distante du runtime client.
flowchart TB
APP[Application C#] --> API[Classes logiCells générées]
API --> CLIENT[IClientRuntime]
CLIENT --> LOCAL[NativeAbiRuntime]
CLIENT --> REMOTE[RpcRuntime]
LOCAL --> ENGINE[logiCells Runtime]
REMOTE --> ENGINE
Statut des exemples
Cette page décrit l'architecture cible du binding .NET. Les noms tels que IClientRuntime, NativeAbiRuntime, RpcRuntime, ObjectRef et les wrappers générés illustratifs expriment le modèle public visé ; ils doivent être vérifiés dans le package généré d'une release précise avant d'être considérés comme des symboles d'API exacts.
Le sous-ensemble ABI natif certifié par le moteur actuel est documenté séparément dans Marshalling et types de valeurs.
Injection explicite du runtime
Le wrapper public reçoit normalement son runtime explicitement. Cette règle rend l'affinité visible et permet d'utiliser plusieurs runtimes dans un même processus.
using rtl.Runtime;
using var runtime = new NativeAbiRuntime("logicells-runtime");
IClientRuntime client = runtime;
// Le type concret ci-dessous dépend du package ABI publié.
using var worker = new AbiWorker(client);
AbiWorker est utilisé dans la documentation du binding lorsqu'il est présent dans la surface publiée. Pour un package applicatif, utilisez toujours le nom public réellement généré par ce package.
Local et RPC
Le même wrapper public peut être utilisé contre un runtime distant :
using rtl.Runtime;
var http = new HttpClient
{
Timeout = TimeSpan.FromSeconds(30)
};
var transport = new HttpJsonTransport(http, endpoint);
IClientRuntime client = new RpcRuntime(transport);
Le changement de topologie ne doit pas modifier le modèle objet de l'application. Il modifie en revanche les caractéristiques opérationnelles : latence, erreurs de transport, authentification, retry et disponibilité.
ObjectRef et identité
ObjectRef identifie un objet Runtime indépendamment du transport. Il porte l'identité nécessaire pour créer, invoquer et libérer l'objet sans exposer son emplacement physique.
Ne comparez pas deux wrappers par référence managée pour conclure qu'ils désignent le même objet Runtime. Utilisez l'identité publiée par le contrat.
CallDescriptor et invocation
Les classes générées utilisent des CallDescriptor en interne. Le développeur applicatif ne doit descendre à ce niveau que pour du tooling ou du diagnostic avancé.
Conceptuellement :
ObjectRef created = runtime.Create(typeId, constructorId, args);
var value = runtime.Invoke<int>(descriptor, created, args);
runtime.Release(created);
La surface normale reste cependant :
using var item = new PublishedItem(runtime);
item.Name = "example";
var state = item.State;
PublishedItem illustre la forme d'un wrapper ; le nom exact doit provenir de l'API générée et certifiée pour le package utilisé.
Durée de vie
Les wrappers propriétaires utilisent IDisposable.
using var item = new PublishedItem(runtime);
La règle est déterministe : un wrapper qui possède une référence Runtime la libère lors de Dispose(). Ne dépendez pas du finalizer pour le fonctionnement normal.
Les objets retournés doivent être documentés comme :
- owned ;
- borrowed ;
- session-scoped ;
- parent-scoped.
Tableaux et objets publiés
Le binding vNext vise un support uniforme des tableaux unidimensionnels de primitives, chaînes et objets publiés.
Pour un tableau d'objets, le binding doit :
- conserver l'affinité au runtime source ;
- connaître le type public de chaque élément ;
- construire le wrapper .NET correspondant ;
- appliquer l'ownership déclaré.
Async
Ne transformez pas artificiellement un appel ABI synchrone en méthode asynchrone publique.
Le binding doit publier Async lorsque le contrat décrit une opération :
- réellement asynchrone ;
- orientée job ;
- streamée ;
- ou annulable selon une sémantique documentée.
L'offload côté client via le thread pool reste une décision de l'application.
Exceptions et diagnostics
Le binding convertit les erreurs du Runtime ou du transport en exceptions .NET appropriées. Les diagnostics doivent conserver autant que possible :
- l'opération concernée ;
- l'identité Runtime ;
- un identifiant de corrélation pour RPC ;
- la capacité ou version de contrat attendue.
Compatibilité au démarrage
Une version d'assembly .NET compatible ne suffit pas à garantir la compatibilité du Runtime. Une application de production doit, lorsque le modèle de déploiement le permet, effectuer une négociation explicite des capacités avant de créer des objets stateful.
Bonnes pratiques
- dépendre de
IClientRuntimeou des wrappers de domaine générés ; - injecter explicitement le runtime ;
- ne pas déplacer des wrappers entre runtimes ;
- utiliser
using/Dispose()pour les objets propriétaires ; - garder les détails de transport hors des types métier ;
- vérifier les capacités au démarrage ;
- consulter le manifest ou la référence API pour les noms publics exacts.
Voir aussi :