Génération de code Orleans
Avant la version 7.0 de Orleans, la génération source était beaucoup plus manuelle et nécessitait une intervention explicite du développeur. À compter de la version 7.0 de Orleans, la génération de code est automatique et ne nécessite aucune intervention du développeur. Toutefois, il existe encore des cas où les développeurs peuvent vouloir influencer la génération de code, par exemple pour générer du code pour des types qui ne sont pas générés automatiquement ou pour générer du code pour des types dans un autre assembly.
Activer la génération de code
Orleans génère du code source C# pour votre application au moment de la génération. Tous les projets, y compris votre hôte, doivent avoir les packages NuGet appropriés installés pour permettre la génération de code. Les packages suivants sont disponibles :
- Tous les clients doivent référencer Microsoft.Orleans.Client.
- Tous les silos (serveurs) doivent référencer Microsoft.Orleans.Server.
- Tous les autres packages doivent référencer Microsoft.Orleans.Sdk.
Utilisez GenerateSerializerAttribute pour spécifier que le type est destiné à être sérialisé et que le code de sérialisation doit être généré pour le type. Pour plus d’informations, consultez Utiliser la sérialisation Orleans.
Le runtime Orleans utilise du code généré pour garantir une bonne sérialisation des types utilisés sur le cluster, mais aussi pour générer du code réutilisable, qui masque les détails d’implémentation de l’expédition des méthodes, de la propagation des exceptions et d’autres concepts d’exécution interne. La génération de code peut être mise en œuvre soit pendant la génération de vos projets soit pendant l’initialisation de votre application.
Que se passe-t-il pendant la génération ?
Au moment de la génération, Orleans génère du code pour tous les types marqués avec GenerateSerializerAttribute. Si un type n’est pas marqué avec GenerateSerializer
, il ne sera pas sérialisé par Orleans.
Si vous développez avec F# ou Visual Basic, vous pouvez également utiliser la génération de code. Pour plus d’informations, consultez les exemples suivants :
Ces exemples montrent comment consommer Orleans.GenerateCodeForDeclaringAssemblyAttribute, en spécifiant des types dans l’assembly pour lesquels le générateur source doit inspecter et générer la source.
Par défaut, la méthode de mise en œuvre de la génération de code intervient en phase de génération de build. La génération de code au moment de la génération de build peut être activée à l’aide de l’un des packages suivants :
- Microsoft.Orleans.OrleansCodeGenerator.Build. Package qui utilise Roslyn pour la génération de code et .NET Reflection pour l’analyse.
- Microsoft.Orleans.CodeGenerator.MSBuild. Nouveau package de génération de code qui tire parti de Roslyn pour la génération de code et l’analyse de code. Il ne charge pas les fichiers binaires d’application et, de ce fait, évite les problèmes causés par les versions de dépendances dissonantes et les frameworks cibles différents. Le nouveau générateur de code améliore aussi la prise en charge des builds incrémentielles, ce qui donne normalement des temps de génération de build plus courts.
Un de ces packages doit être installé dans tous les projets qui contiennent des grains, des interfaces de grain, des sérialiseurs personnalisés ou des types envoyés entre les grains. L’installation d’un package injecte une cible dans le projet qui génère du code au moment de la génération de build.
Les deux packages (Microsoft.Orleans.CodeGenerator.MSBuild
et Microsoft.Orleans.OrleansCodeGenerator.Build
) prennent uniquement en charge les projets C#. D’autres langages sont pris en charge. Pour cela, il convient d’utiliser le package Microsoft.Orleans.OrleansCodeGenerator
décrit ci-dessous ou de créer un projet C# qui peut servir de cible pour le code généré à partir d’assemblys écrits dans d’autres langages.
Des diagnostics supplémentaires peuvent être émis au moment de la génération de build en spécifiant une valeur pour OrleansCodeGenLogLevel
dans le fichier .csproj du projet cible. Par exemple : <OrleansCodeGenLogLevel>Trace</OrleansCodeGenLogLevel>
.
Que se passe-t-il pendant l’initialisation ?
Dans les versions 7 et supérieures de Orleans, rien ne se passe pendant l’initialisation. La génération de code s’effectue au moment de la génération.
La génération de code peut être mise en œuvre pendant l’initialisation sur le client et le silo en installant le package Microsoft.Orleans.OrleansCodeGenerator
et en utilisant la méthode d’extension ApplicationPartManagerCodeGenExtensions.WithCodeGeneration :
builder.ConfigureApplicationParts(
parts => parts
.AddApplicationPart(typeof(IRuntimeCodeGenGrain).Assembly)
.WithCodeGeneration());
Dans l’exemple précédent, builder
peut être une instance de ISiloHostBuilder ou IClientBuilder.
Une instance facultative de ILoggerFactory peut être transmise à WithCodeGeneration
pour activer la journalisation pendant la génération de code, par exemple :
ILoggerFactory codeGenLoggerFactory = new LoggerFactory();
codeGenLoggerFactory.AddProvider(new ConsoleLoggerProvider());
builder.ConfigureApplicationParts(
parts => parts
.AddApplicationPart(typeof(IRuntimeCodeGenGrain).Assembly)
.WithCodeGeneration(codeGenLoggerFactory));
Influencer la génération de code
Lors de l’application GenerateSerializerAttribute à un type, vous pouvez également appliquer IdAttribute pour identifier de manière unique le membre. De même, vous pouvez également appliquer un alias avec AliasAttribute. Pour plus d’informations sur l’influence sur la génération de code, consultez Utiliser la sérialisation Orleans.
Pendant la génération de code, vous pouvez influencer la génération de code pour un type spécifique. Le code est automatiquement généré pour les interfaces de grain, les classes de grain, l’état de grain et les types transmis en tant qu’arguments dans les méthodes de grain. Si un type ne répond pas à ces critères, les méthodes suivantes peuvent être utilisées pour guider davantage la génération de code.
L’ajout de SerializableAttribute à un type donne instruction au générateur de code de générer un sérialiseur pour ce type.
L’ajout de [assembly: GenerateSerializer(Type)]
à un projet donne instruction au générateur de code de considérer ce type comme étant sérialisable et provoque une erreur si un sérialiseur n’a pas pu être généré pour ce type, par exemple, en raison de l’inaccessibilité de ce type. Cette erreur interrompt la génération de build si la génération de code est activée. Cet attribut permet aussi de générer du code pour des types spécifiques issus d’un autre assembly.
Par ailleurs, [assembly: KnownType(Type)]
demande au générateur de code d’inclure un type spécifique (qui peut provenir d’un assembly référencé), mais ne provoque pas d’exception si le type est inaccessible.
Générer des sérialiseurs pour tous les sous-types
L’ajout de KnownBaseTypeAttribute à une interface ou une classe donne instruction au générateur de code de générer du code de sérialisation pour tous les types qui héritent/implémentent ce type.
Générer du code pour tous les types d’un autre assembly
Il existe des cas où le code généré ne peut pas être inclus dans un assembly déterminé au moment de la génération de build. Cela peut inclure, par exemple, les bibliothèques partagées qui ne font pas référence à Orleans, les assemblys écrits dans des langages autres que C# et les assemblys dont le développeur ne dispose pas du code source. En pareils cas, le code généré pour ces assemblys peut être placé dans un assembly distinct référencé pendant l’initialisation.
Pour activer cette option pour un assembly :
- Créez un projet C#.
- Installer le package
Microsoft.Orleans.CodeGenerator.MSBuild
ouMicrosoft.Orleans.OrleansCodeGenerator.Build
. - Ajoutez une référence à l’assembly cible.
- Ajoutez
[assembly: KnownAssembly("OtherAssembly")]
au niveau supérieur d’un fichier C#.
KnownAssemblyAttribute donne instruction au générateur de code d’inspecter l’assembly spécifié et de générer du code pour les types qu’il contient. L’attribut peut être utilisé plusieurs fois dans un projet.
L’assembly généré doit ensuite être ajouté au client/silo pendant l’initialisation :
builder.ConfigureApplicationParts(
parts => parts.AddApplicationPart("CodeGenAssembly"));
Dans l’exemple précédent, builder
peut être une instance de ISiloHostBuilder ou IClientBuilder.
KnownAssemblyAttribute
possède une propriété facultative, TreatTypesAsSerializable, qui peut être définie sur true
pour indiquer au générateur de code de faire comme si tous les types de cet assembly étaient marqués comme étant sérialisables.