
Aujourd'hui, Microsoft a une version passionnante comprenant de nombreuses mises à jour de bibliothèques, un nouveau mode WASM, plus de générateurs de sources, des améliorations constantes des performances et le support de NativeAOT sur iOS. Microsoft espére que vous apprécierez ces nouvelles fonctionnalités et améliorations.
Vous pouvez télécharger .NET 8 Preview 6 pour Linux, macOS et Windows.
Restez au courant de ce qui est nouveau et à venir dans What's New in .NET 8. Il sera mis à jour tout au long de la publication.
Jetons maintenant un coup d'œil à quelques nouvelles fonctionnalités de .NET 8.
Améliorations apportées à System.Text.Json
Microsoft a apporté un certain nombre d'améliorations au générateur de sources System.Text.Json, principalement dans le but de rendre Native AOT comparable au serializer basé sur la réflexion.
- Ajout du support de la mise en cache au générateur incrémental, améliorant ainsi les performances de l'IDE dans les grands projets. https://github.com/dotnet/runtime/pull/86121
- Amélioration du formatage du code source généré, y compris des corrections pour un certain nombre de problèmes d'indentation https://github.com/dotnet/runtime/pull/86526, https://github.com/dotnet/runtime/pull/87557
- Ajout d'un certain nombre de nouveaux avertissements de diagnostic https://github.com/dotnet/runtime/pull/87980
- Correction d'un certain nombre de bogues liés à la résolution des modificateurs d'accessibilité https://github.com/dotnet/runtime/pull/87136
- Veille à ce que les types de propriétés ignorées ou inaccessibles ne soient pas inclus par le générateur https://github.com/dotnet/runtime/pull/87383
- Correction de problèmes liés à la prise en charge de JsonNumberHandling https://github.com/dotnet/runtime/pull/87484
- Correction de la prise en charge des types de collection récursifs https://github.com/dotnet/runtime/pull/87632
- Correction de la prise en charge des convertisseurs personnalisés pour les structures nullables https://github.com/dotnet/runtime/pull/84208
- Correction d'un certain nombre de bogues dans l'implémentation de l'analyse d'attributs à la compilation https://github.com/dotnet/runtime/pull/87796
- Ajout de la prise en charge de l'imbrication des déclarations JsonSerializerContext dans des types arbitraires https://github.com/dotnet/runtime/pull/87829
JsonStringEnumConverter<TEnum>
Ce nouveau convertisseur complète la classe JsonStringEnumConverter existante, qui n'est pas prise en charge par Native AOT.
Les utilisateurs souhaitant cibler les utilisateurs de Native AOT doivent annoter leurs types d'énumération avec le modèle suivant.
Code : | Sélectionner tout |
1 2 3 4 5 | [JsonConverter(typeof(JsonStringEnumConverter<MyEnum>))] public enum MyEnum { Value1, Value2, Value3 } [JsonSerializable(typeof(MyEnum))] public partial class MyContext : JsonSerializerContext { } |
JsonConverter.Type
Cette nouvelle propriété permet aux utilisateurs de connaître le type d'une instance non générique de JsonConverter :
Code : | Sélectionner tout |
1 2 | Dictionary<Type, JsonConverter> CreateDictionary(IEnumerable<JsonConverter> converters) => converters.Where(converter => converter.Type != null).ToDictionary(converter => converter.Type!); |
La propriété est annulable puisqu'elle renvoie null pour les instances de JsonConverterFactory et typeof(T) pour les instances de JsonConverter<T>.
Surcharge des méthodes ZipFile.CreateFromDirectory et ExtractToDirectory basées sur les flux
Microsoft a ajouté de nouvelles surcharges de ZipFile CreateFromDirectory qui permettent aux utilisateurs de collecter tous les fichiers inclus dans un répertoire et de les zipper, puis de stocker le fichier zip résultant dans le flux fourni.
Symétriquement les surcharges ont été ajouté ZipFile CreateFromDirectory qui permettent aux utilisateurs de fournir un flux contenant un fichier zippé et d'extraire son contenu dans le système de fichiers.
Ces API permettent d'éviter d'utiliser le disque comme étape intermédiaire. Cela peut être utile dans les scénarios où l'espace disque est limité, comme, par exemple, dans les environnements basés sur le cloud :
- CreateFromDirectory n'a pas besoin d'écrire le résultat zippé sur le disque.
- ExtractToDirectory ne nécessite pas que le fichier zippé soit situé sur le disque.
Utilisation de ZipFile.CreateFromDirectory
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 | Stream destinationStream = GetStreamFromSomewhere(); ZipFile.CreateFromDirectory( sourceDirectoryName: "/home/username/sourcedirectory/", destination: destinationStream, compressionLevel: CompressionLevel.Optimal, includeBaseDirectory: true, entryNameEncoding: Encoding.UTF8); |
Code : | Sélectionner tout |
1 2 3 4 5 6 7 | Stream sourceStream = GetStreamFromSomewhere(); ZipFile.ExtractToDirectory( source: sourceStream, destinationDirectoryName: "/home/username/destinationdirectory/", entryNameEncoding: Encoding.UTF8, overwriteFiles: true); |
MetricCollector est une nouvelle classe conçue pour aider à tester des scénarios. Il s'appelait auparavant InstrumentRecorder. Microsoft a apporté des améliorations significatives à cette classe et l'as déplacée vers le package Microsoft.Extensions.Telemetry.Testing.
La classe MetricCollector peut désormais enregistrer des mesures métriques avec des horodatages. De plus, la classe offre la possibilité d'utiliser n'importe quel fournisseur de temps souhaité pour une génération d'horodatage précise.
L'exemple suivant montre comment utiliser la fonctionnalité.
Usage de MetricCollector
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | const string CounterName = "MyCounter"; var now = DateTimeOffset.Now; var timeProvider = new FakeTimeProvider(now); using var meter = new Meter(Guid.NewGuid().ToString()); var counter = meter.CreateCounter<long>(CounterName); using var collector = new MetricCollector<long>(counter, timeProvider); Assert.Empty(collector.GetMeasurementSnapshot()); Assert.Null(collector.LastMeasurement); counter. Add(3); // verify the update was recorded Assert.Equal(counter, collector.Instrument); Assert.NotNull(collector.LastMeasurement); Assert.Single(collector.GetMeasurementSnapshot()); Assert.Same(collector.GetMeasurementSnapshot().Last(), collector.LastMeasurement); Assert.Equal(3, collector.LastMeasurement.Value); Assert.Empty(collector.LastMeasurement.Tags); Assert.Equal(now, collector.LastMeasurement.Timestamp); |
Présentation du générateur de source de validation des options
Pour réduire les frais de démarrage et améliorer l'ensemble des fonctionnalités de validation, Microsoft a introduit le générateur de code source qui implémente la logique de validation.
Utilisation de la validation des options
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | public class FirstModelNoNamespace { [Required] [MinLength(5)] public string P1 { get; set; } = string. Empty; [Microsoft.Extensions.Options.ValidateObjectMembers(typeof(SecondValidatorNoNamespace))] public SecondModelNoNamespace? P2 { get; set; } [Microsoft.Extensions.Options.ValidateObjectMembers] public ThirdModelNoNamespace? P3 { get; set; } } public class SecondModelNoNamespace { [Required] [MinLength(5)] public string P4 { get; set; } = string. Empty; } public class ThirdModelNoNamespace { [Required] [MinLength(5)] public string P5 { get; set; } = string.Empty; } [OptionsValidator] public partial class FirstValidatorNoNamespace : IValidateOptions<FirstModelNoNamespace> { } [OptionsValidator] public partial class SecondValidatorNoNamespace : IValidateOptions<SecondModelNoNamespace> { } |
Code : | Sélectionner tout |
1 2 3 4 5 6 | var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllersWithViews(); builder.Services.Configure<FirstModelNoNamespace>(builder.Configuration.GetSection(...)); builder.Services.AddSingleton<IValidateOptions<FirstModelNoNamespace>, FirstValidatorNoNamespace>(); builder.Services.AddSingleton<IValidateOptions<SecondModelNoNamespace>, SecondValidatorNoNamespace>(); |
De nouvelles surcharges de constructeur LoggerMessageAttribute ont été introduites, offrant une plus grande flexibilité dans la spécification des paramètres requis avec un code réduit. Les nouvelles surcharges de constructeur incluent des options telles que la spécification uniquement du LogLevel et du message, uniquement du LogLevel ou uniquement du message.
Ces améliorations permettent aux utilisateurs de définir plus facilement les LoggerMessageAttributes tout en minimisant le code inutile.
Code : | Sélectionner tout |
1 2 3 | public LoggerMessageAttribute(LogLevel level, string message); public LoggerMessageAttribute(LogLevel level); public LoggerMessageAttribute(string message); |
Utilisation de LoggerMessage
L'exemple suivant illustre une instanciation de LoggerMessage qui n'était pas possible auparavant.
Code : | Sélectionner tout |
1 2 | [LoggerMessage(Level = LogLevel.Warning, Message = "{p1} should be valid")] public partial void LogWaraning(string p1); |
Améliorations du générateur de source de liaison de configuration
Dans Preview 3, Microsoft a introduit un nouveau générateur de source pour fournir une configuration AOT et compatible avec le trim dans ASP.NET Core. Le générateur est une alternative à la mise en œuvre préexistante basée sur la réflexion. Depuis lors, nous avons apporté plusieurs améliorations basées sur les commentaires de la communauté et le générateur est prêt à être réutilisé avec Preview 6.
Un exemple d'application qui utilise la liaison de configuration et est publiée avec AOT passe de deux (2) avertissements d'analyse AOT lors de la compilation à aucun. L'application échouerait lors de son exécution, mais maintenant elle fonctionne.
Aucune modification du code source n'est nécessaire pour utiliser le générateur. Il est activé par défaut dans les applications Web Native AOT. Pour les autres types de projets, il est désactivé par défaut, mais vous pouvez le contrôler en ajoutant la propriété suivante à votre projet.
Code : | Sélectionner tout |
1 2 3 | <PropertyGroup> <EnableConfigurationBindingGenerator>true</EnableConfigurationBindingGenerator> </PropertyGroup> |
Interopérabilité COM générée par la source
Microsoft a maintenant un nouveau générateur de source qui prend en charge l'interopérabilité avec les interfaces COM à l'aide de la prise en charge de l'interopérabilité générée par la source que nous avons démarrée avec LibraryImportAttribute. Vous pouvez utiliser System.Runtime.InteropServices.Marshalling.GeneratedComInterfaceAttribute pour marquer une interface comme interface COM pour le générateur source. Le générateur de source générera ensuite du code pour permettre l'appel du code C# vers du code non managé, ainsi que du code pour permettre l'appel du code non managé vers C#. Ce générateur de source s'intègre à LibraryImportAttribute et vous pouvez utiliser des types avec GeneratedComInterfaceAttribute comme paramètres et types de retour dans les méthodes attribuées par LibraryImportAttribute.
Le générateur de source COM offre une expérience IDE simple grâce à des analyseurs et des fixateurs de code. Ceci est similaire à LibraryImportAttribute. À côté de chaque interface qui a le System.Runtime.InteropServices.ComImportAttribute, une ampoule offrira une option pour convertir en interopérabilité générée par la source. Ce correctif modifiera l'interface pour utiliser GeneratedComInterfaceAttribute. À côté de chaque classe qui implémente une interface avec le GeneratedComInterfaceAttribute, une ampoule offrira une option pour ajouter le GeneratedComInterfaceAttribute au type. Une fois vos types convertis, vous pouvez déplacer vos méthodes DllImport pour utiliser LibraryImportAttribute avec le fixateur de code existant. Avec ces deux ampoules, il est facile de convertir votre code d'interopérabilité COM existant pour utiliser la nouvelle interopérabilité générée par la source. Il existe également d'autres analyseurs pour vous aider à identifier les endroits où vous pouvez mélanger l'interopérabilité COM générée par la source et basée sur l'exécution qui peut nécessiter un travail supplémentaire.
Dans le cadre de ce projet, nous avons mis à jour la bibliothèque System.Transactions pour utiliser la nouvelle interopérabilité générée par la source ! Nous avons utilisé cette expérience pour aider à affiner les analyseurs et les correcteurs de code afin de fournir une bonne expérience de migration.
Usage de GeneratedComInterfaceAttribute
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | using System.Runtime.InteropServices; using System.Runtime.InteropServices.Marshalling; [GeneratedComInterface] [Guid("5401c312-ab23-4dd3-aa40-3cb4b3a4683e")] interface IComInterface { void DoWork(); } internal class MyNativeLib { [LibraryImport(nameof(MyNativeLib))] public static partial void GetComInterface(out IComInterface comInterface); } |
GeneratedComClassAttribute
Le générateur source prend également en charge le nouveau System.Runtime.InteropServices.Marshalling.GeneratedComClassAttribute pour vous permettre de transmettre vos types qui implémentent des interfaces avec les interfaces attribuées par System.Runtime.InteropServices.Marshalling.GeneratedComInterfaceAttribute au code non managé. Le générateur de source générera le code nécessaire pour exposer un objet COM qui implémente les interfaces et transmet les appels à l'implémentation managée.
Usage de GeneratedComClassAttribute
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | using System.Runtime.InteropServices; using System.Runtime.InteropServices.Marshalling; MyNativeLib.GetComInterface(out IComInterface comInterface); comInterface.RegisterCallbacks(new MyCallbacks()); comInterface.DoWork(); [GeneratedComInterface] [Guid("5401c312-ab23-4dd3-aa40-3cb4b3a4683e")] interface IComInterface { void DoWork(); void RegisterCallbacks(ICallbacks callbacks); } [GeneratedComInterface] [Guid("88470b56-aabc-46af-bf97-8106a1aa3cf9")] interface ICallbacks { void Callback(); } internal class MyNativeLib { [LibraryImport(nameof(MyNativeLib))] public static partial void GetComInterface(out IComInterface comInterface); } [GeneratedComClass] internal class MyCallbacks : ICallbacks { public void Callback() { Console.WriteLine("Callback called"); } } |
Les méthodes sur les interfaces avec GeneratedComInterfaceAttribute prennent en charge tous les mêmes types que LibraryImportAttribute, et LibraryImportAttribute prend en charge les types attribués par GeneratedComInterface et les types attribués par GeneratedComClass dans cette version.
Si votre code C# n'utilisera qu'une interface attribuée par GeneratedComInterfaceAttribute pour encapsuler un objet COM à partir de code non managé ou encapsuler un objet managé à partir de C# pour l'exposer à du code non managé, vous pouvez utiliser les options de la propriété GeneratedComInterfaceAttribute.Options pour personnaliser le code sera généré. Cette option vous permettra de ne pas avoir à écrire de marshallers pour des scénarios dont vous savez qu'ils ne seront pas utilisés.
Le générateur source utilise le nouveau type
System.Runtime.InteropServices.Marshalling.StrategyBasedComWrappers pour créer et gérer les wrappers d'objets COM et les wrappers d'objets gérés. Ce nouveau type gère l'expérience utilisateur .NET attendue pour l'interopérabilité COM, tout en fournissant des points de personnalisation pour les utilisateurs avancés. Si votre application dispose de son propre mécanisme pour définir des types à partir de COM ou si vous devez prendre en charge des scénarios que COM généré par la source ne prend pas actuellement en charge, vous pouvez envisager d'utiliser le nouveau type StrategyBasedComWrappers pour ajouter les fonctionnalités manquantes à votre scénario et obtenir le même .NET expérience utilisateur pour vos types COM.
Limites
Actuellement, le générateur de source COM présente les limitations suivantes. Nous ne prévoyons pas de résoudre ces limitations dans .NET 8, mais nous le pourrons dans une future version de .NET.
- Pas de prise en charge des interfaces basées sur IDispatch.
*La prise en charge de ces interfaces peut être implémentée manuellement à l'aide d'une définition locale de l'interface IDispatch.
- Pas de prise en charge des interfaces basées sur IInspectable.
*Utilisez l'outil CsWinRT pour générer le code d'interopérabilité pour ces interfaces.
- Pas de prise en charge de l'affinité d'appartement.
*Tous les objets COM sont supposés être à thread libre. La prise en charge de l'affinité d'appartement peut être implémentée manuellement à l'aide du type StrategyBasedComWrappers et des implémentations de stratégie personnalisées.
- Pas de prise en charge des propriétés COM.
*Celles-ci peuvent être implémentées manuellement en tant que méthodes sur l'interface.
- Pas de prise en charge des événements COM.
*Celles-ci peuvent être implémentées manuellement à l'aide des API COM sous-jacentes.
- Aucune prise en charge de l'utilisation d’un new mot-clé pour activer une coclasse COM.
*Utilisez LibraryImportAttribute pour P/Invoke à l'API CoCreateInstance pour activer la CoClass.
Prise en charge du proxy HTTPS
https://github.com/dotnet/runtime/issues/31113
Bien que HttpClient ait pris en charge divers types de proxy pendant un certain temps, ils permettent tous à l'homme du milieu de voir à quel site le client se connecte. (même pour les URI HTTPS) Le proxy HTTPS permet de créer un canal crypté entre le client et le proxy afin que toutes les requêtes ultérieures puissent être traitées en toute confidentialité.
Utilisation du proxy HTTPS
- Unix : export all_proxy=https://x.x.x.x:3218
- Windows : [C]set all_proxy=https://x.x.x.x:3218[/C
]
System.Security : Prise en charge de SHA-3
La prise en charge des primitives de hashing SHA-3 est désormais disponible sur les plateformes qui proposent SHA-3. Il s'agit actuellement de Linux avec OpenSSL 1.1.1+ et Windows 11 build 25324+.
Les API où SHA-2 est disponible offrent désormais un complément SHA-3. Cela inclut SHA3_256, SHA3_384 et SHA3_512 pour le hashing ; HMACSHA3_256, HMACSHA3_384 et HMACSHA3_512 pour HMAC ; HashAlgorithmName.SHA3_256, HashAlgorithmName.SHA3_384 et HashAlgorithmName.SHA3_512 pour le hashing où l'algorithme est configurable ; et RSAEncryptionPadding.OaepSHA3_256, RSAEncryptionPadding.OaepSHA3_384 et RSAEncryptionPadding.OaepSHA3_512 pour le chiffrement RSA OAEP.
L'utilisation des API SHA-3 est similaire à SHA-2, avec l'ajout d'une propriété IsSupported pour déterminer si la plateforme offre SHA-3.
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | // Hashing example // Check if SHA-3-256 is supported on the current platform. if (SHA3_256.IsSupported) { byte[] hash = SHA3_256.HashData(dataToHash); } else { // Determine application behavior if SHA-3 is not available. } // Signing Example // Check if SHA-3-256 is supported on the current platform. if (SHA3_256.IsSupported) { using ECDsa ec = ECDsa.Create(ECCurve.NamedCuves.nistP256); byte[] signature = ec.SignData(dataToBeSigned, HashAlgorithmName.SHA3_256); } else { // Determine application behavior if SHA-3 is not available. } |
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 | if (Shake128.IsSupported) { using Shake128 shake = new Shake128(); shake.AppendData("Hello .NET!"u8); byte[] digest = shake.GetHashAndReset(outputLength: 32); // Also available as a one-shot: digest = Shake128.HashData("Hello .NET!"u8, outputLength: 32); } else { // Determine application behavior if SHAKE is not available. } |
SHA-3 a été normalisé par le NIST en tant que FIPS 202 comme alternative, et non comme successeur, à SHA-2. Les développeurs et les organisations doivent décider quand ou même si l'adoption de SHA-3 leur convient.
SDK : performances et compatibilité de la publication de conteneurs
Nous avons apporté quelques modifications aux valeurs par défaut des images générées pour les applications .NET 8.
- Les images utilisent désormais par défaut la nouvelle capacité sans racine des conteneurs .NET, ce qui rend vos applications sécurisées par défaut. Vous pouvez changer cela à tout moment en définissant votre propre ContainerUser, comme root.
- Les images sont étiquetées comme latest par défaut, comme les autres outils de conteneur.
Microsoft a amélioré les performances des poussées de conteneurs vers des registres distants, la fiabilité de l'opération de poussée et la prise en charge d'un plus grand nombre de registres. Dans le même temps, Tom Deseyn de Red Hat était occupé à améliorer la prise en charge d'une gamme d'implémentations de conteneurs courantes.
Cette version devrait voir des performances nettement améliorées pour les poussées de conteneurs, en particulier vers les registres Azure. Cela est dû à notre prise en charge améliorée pour pousser les couches en une seule opération. De plus, pour les registres qui ne prennent pas en charge les téléchargements atomiques, Microsoft a mis en place un mécanisme de téléchargement par blocs plus fiable et réessayable.
Comme effet secondaire de ces changements, Microsoft a également élargi sa matrice de support pour les registres. Harbour et Artifactory rejoignent la liste des registres de travail connus, et le travail de Tom a également permis à Quay.io et Podman de pousser.
Mode HybridGlobalization sur WASM
Les applications WASM peuvent utiliser un nouveau mode de globalisation qui allège l'ensemble ICU et exploite l'API Web à la place. En mode hybride, les données de globalisation sont partiellement extraites du bundle ICU et partiellement des appels vers JS. Il dessert tous les paramètres régionaux pris en charge par WASM.
Quand envisager d'utiliser HybridGlobalization
Cette option est la plus appropriée pour les applications...
La fin de cet article est réservée aux abonnés. Soutenez le Club Developpez.com en prenant un abonnement pour que nous puissions continuer à vous proposer des publications.