Condividi tramite


Novità di .NET Core 3.0

Questo articolo descrive le novità di .NET Core 3.0. Uno dei principali miglioramenti è il supporto per le applicazioni desktop di Windows (solo Windows). Con il componente Windows Desktop di .NET Core 3.0 SDK, è possibile convertire le applicazioni Windows Forms e WPF (Windows Presentation Foundation). Il componente Windows Desktop è dunque supportato e incluso solo in Windows. Per altre informazioni, vedere la sezione Desktop di Windows più avanti in questo articolo.

.NET Core 3.0 aggiunge il supporto per C# 8.0. È consigliabile usare Visual Studio 2019 versione 16.3 o successiva o Visual Studio Code con l'estensione C# più recente.

Scaricare e iniziare subito a usare .NET Core 3.0 in Windows, macOS o Linux.

Per altre informazioni sulla versione, vedere l'annuncio di .NET Core 3.0.

.NET Core 3.0 RC 1 è stato considerato pronto per la produzione e completamente supportato da Microsoft. Se si usa una versione di anteprima, è necessario passare alla versione RTM per il supporto continuo.

Miglioramenti del linguaggio C# 8.0

Anche C# 8.0 fa parte di questa versione, che include la funzionalità dei tipi di riferimento nullable, i flussi asincroni e altri modelli. Per altre informazioni sulle funzionalità di C# 8.0, vedere Novità di C# 8.0.

Esercitazioni correlate alle funzionalità del linguaggio C# 8.0:

Sono stati aggiunti miglioramenti del linguaggio per supportare le seguenti funzionalità API descritte di seguito:

.NET Standard 2.1

.NET Core 3.0 implementa .NET Standard 2.1. Tuttavia, il modello predefinito dotnet new classlib genera un progetto che è ancora destinato a .NET Standard 2.0. Per destinarlo a .NET Standard 2.1, modificare il file di progetto e la proprietà TargetFramework in netstandard2.1:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netstandard2.1</TargetFramework>
  </PropertyGroup>

</Project>

Se si usa Visual Studio, è necessario Visual Studio 2019 perché Visual Studio 2017 non supporta .NET Standard 2.1 o .NET Core 3.0.

Compilazione/distribuzione

File eseguibili predefiniti

Per impostazione predefinita .NET Core ora compila file eseguibili dipendenti dal framework. Si tratta di una novità per le applicazioni che usano una versione di .NET Core installata a livello globale. In precedenza solo le distribuzioni autonome generavano un file eseguibile.

Durante dotnet build o dotnet publish, viene creato un file eseguibile (noto come appHost) che corrisponde all'ambiente e alla piattaforma dell'SDK in uso. Il comportamento di questi file eseguibili è uguale a quello degli altri file eseguibili nativi, ad esempio:

  • È possibile fare doppio clic sul file eseguibile.
  • È possibile avviare l'applicazione direttamente da un prompt dei comandi, ad esempio myapp.exe in Windows e ./myapp in Linux e macOS.

appHost macOS e autenticazione

Solo macOS

A partire da .NET Core SDK 3,0 autenticato per macOS, l'impostazione per produrre un eseguibile predefinito (noto come appHost) è disabilitata per impostazione predefinita. Per altre informazioni, vedere Autenticazione di macOS Catalina e impatto su download e progetti .NET Core.

Quando l'impostazione appHost è abilitata, .NET Core genera un eseguibile Mach-O nativo durante la compilazione o la pubblicazione. L'app viene eseguita nel contesto di appHost quando viene eseguita dal codice sorgente con il comando dotnet run o avviando direttamente il file eseguibile Mach-O.

Senza appHost, l'unico modo in cui un utente può avviare un'app dipendente dal framework è tramite il comando dotnet <filename.dll>. Un appHost viene sempre creato quando si pubblica l'app autonoma.

È possibile configurare appHost a livello di progetto, oppure attivarlo o disattivarlo per uno specifico comando dotnet con il parametro -p:UseAppHost:

  • File di progetto

    <PropertyGroup>
      <UseAppHost>true</UseAppHost>
    </PropertyGroup>
    
  • Parametro della riga di comando

    dotnet run -p:UseAppHost=true
    

Per altre informazioni sull'UseAppHostimpostazione, vedere Proprietà di MSBuild per Microsoft.NET.Sdk.

File eseguibili singoli

Il comando dotnet publish supporta la creazione del pacchetto dell'app come file eseguibile singolo specifico per la piattaforma. Il file eseguibile è autoestraente e contiene tutte le dipendenze (incluse quelle native) necessarie per eseguire l'app. Quando l'app viene eseguita per la prima volta, l'applicazione viene estratta in una directory in base al nome dell'app e all'identificatore di compilazione. L'avvio dell'applicazione sarà più veloce alla successiva esecuzione. L'applicazione non dovrà ripetere l'estrazione una seconda volta, a meno che sia stata usata una nuova versione.

Per pubblicare un file eseguibile singolo, impostare PublishSingleFile nel progetto o nella riga di comando usando il comando dotnet publish:

<PropertyGroup>
  <RuntimeIdentifier>win10-x64</RuntimeIdentifier>
  <PublishSingleFile>true</PublishSingleFile>
</PropertyGroup>

-o-

dotnet publish -r win10-x64 -p:PublishSingleFile=true

Per altre informazioni sulla pubblicazione di file singolo, vedere il documento sulla progettazione di un bundler con file singolo.

Taglio dell'assembly

.NET Core SDK 3.0 include uno strumento che consente di ridurre le dimensioni delle app analizzando il linguaggio intermedio (IL) e rimuovendo gli assembly inutilizzati.

Le app autonome includono tutti gli elementi necessari per eseguire il codice, senza richiedere l'installazione di .NET nel computer host. Tuttavia, per il funzionamento dell'app è spesso sufficiente un piccolo subset del framework, mentre altre librerie inutilizzate possono essere rimosse.

.NET Core include ora un'impostazione che consente l'uso dello strumento IL Trimmer per analizzare il linguaggio intermedio dell'app. Questo strumento rileva il codice necessario e quindi rimuove le librerie inutilizzate. Può quindi ridurre notevolmente le dimensioni di distribuzione di alcune app.

Per abilitare questo strumento, aggiungere l'impostazione <PublishTrimmed> nel progetto e pubblicare un'app autonoma:

<PropertyGroup>
  <PublishTrimmed>true</PublishTrimmed>
</PropertyGroup>
dotnet publish -r <rid> -c Release

Ad esempio, il nuovo modello predefinito per un progetto di console di base "hello world" ha una dimensione di circa 70 MB quando viene pubblicato. Usando <PublishTrimmed> la dimensione viene ridotta fino a circa 30 MB.

È importante tenere presente che le applicazioni o i framework, inclusi ASP.NET Core e WPF, che usano la reflection o le funzionalità dinamiche correlate, sono spesso soggetti a interruzioni in caso di rimozione di assembly. Questa interruzione si verifica perché il trimmer non è a conoscenza di questo comportamento dinamico e non è in grado di determinare quali tipi di framework sono necessari per la reflection. Lo strumento IL Trimmer può essere configurato in modo da riconoscere questo scenario.

È importante soprattutto accertarsi di testare l'app dopo la rimozione degli assembly inutilizzati.

Per altre informazioni sullo strumento IL Trimmer, vedere la documentazione o visitare il repository mono/linker.

Compilazione a livelli

Per impostazione predefinita, con .NET Core 3.0 la compilazione a livelli è attiva. Questa funzionalità consente al runtime di usare in modo più adattivo il compilatore just-in-time (JIT) per ottenere prestazioni migliori.

Il vantaggio principale della compilazione a più livelli è quello di fornire due modalità di jitting: in un livello di qualità inferiore ma più veloce, oppure in un livello di qualità superiore ma più lento. La qualità si riferisce al livello di ottimizzazione del metodo. TC consente di migliorare le prestazioni di un'applicazione durante le diverse fasi di esecuzione, dall'avvio allo stato stazionario. Quando la compilazione a livelli è disabilitata, ogni metodo viene compilato in un unico modo che è influenzato dalle prestazioni dello stato stazionario rispetto alle prestazioni di avvio.

Quando il TC è abilitato, si applica il seguente comportamento per la compilazione dei metodi all'avvio dell'applicazione:

  • Se il metodo dispone di codice compilato in anticipo o ReadyToRun, viene usato il codice pregenerato.
  • In caso contrario, il metodo è Just-In-Time. In genere, questi metodi sono generici rispetto ai tipi di valore.
    • Quick JIT produce codice di qualità inferiore (o meno ottimizzato) più rapidamente. In .NET Core 3.0, Quick JIT è abilitato per impostazione predefinita nei metodi che non contengono cicli ed è preferibile durante l'avvio.
    • L'ottimizzazione completa di JIT produce codice di qualità superiore (o più ottimizzato) più lentamente. Per i metodi in cui Quick JIT non viene usato (ad esempio, se il metodo è attribuito a MethodImplOptions.AggressiveOptimization), si usa il JIT con ottimizzazione completa.

Per i metodi chiamati frequentemente, il compilatore JIT crea infine codice completamente ottimizzato in background. Il codice ottimizzato sostituisce quindi il codice precompilato per tale metodo.

Il codice generato da QUICK JIT può essere eseguito più lentamente, allocare più memoria o usare più spazio nello stack. In caso di problemi, è possibile disabilitare Quick JIT usando la seguente proprietà MSBuild nel file di progetto:

<PropertyGroup>
  <TieredCompilationQuickJit>false</TieredCompilationQuickJit>
</PropertyGroup>

Per disabilitare completamente TC, usare la seguente proprietà MSBuild nel file di progetto:

<PropertyGroup>
  <TieredCompilation>false</TieredCompilation>
</PropertyGroup>

Suggerimento

Se si modificano queste impostazioni nel file di progetto, potrebbe essere necessario eseguire una compilazione pulita affinché le nuove impostazioni vengano applicate (eliminare obj e le directory bin e ricompilare).

Per altre informazioni sulla configurazione della compilazione in fase di esecuzione, vedere Opzioni di configurazione di runtime per la compilazione.

Immagini ReadyToRun

È possibile migliorare il tempo di avvio delle applicazioni .NET Core compilando gli assembly nel formato ReadyToRun (R2R). R2R è un formato di compilazione AOT (Ahead-of-time).

I file binari R2R migliorano le prestazioni di avvio riducendo la quantità di lavoro che deve eseguire il compilatore JIT (Just-in-time) durante il caricamento dell'applicazione. I file binari contengono codice nativo simile a ciò che viene generato dal compilatore JIT. I file binari R2R, tuttavia, sono più grandi poiché contengono sia il codice in linguaggio intermedio, che è comunque necessario per alcuni scenari, sia la versione nativa dello stesso codice. R2R è disponibile solo quando si pubblica un'app autonoma che fa riferimento ad ambienti di runtime specifici (RID), ad esempio Linux x64 o Windows x64.

Per compilare il progetto come ReadyToRun, seguire questa procedura:

  1. Aggiungere l'impostazione <PublishReadyToRun> al progetto:

    <PropertyGroup>
      <PublishReadyToRun>true</PublishReadyToRun>
    </PropertyGroup>
    
  2. Pubblicare un'app autonoma. Questo comando, ad esempio, crea un'app autonoma per la versione a 64 bit di Windows:

    dotnet publish -c Release -r win-x64 --self-contained
    

Limitazioni per ambienti con più piattaforme o architetture

Il compilatore ReadyToRun attualmente non supporta la definizione di più destinazioni. La compilazione deve essere eseguita per una determinata destinazione. Se, ad esempio, si vogliono immagini R2R per Windows x64, è necessario eseguire il comando di pubblicazione in tale ambiente.

Eccezioni relative all'uso di più destinazioni:

  • Windows x64 può essere usato per compilare immagini Windows Arm32, Arm64 e x86.
  • Windows x86 può essere usato per compilare immagini Windows Arm32.
  • Linux x64 può essere usato per compilare immagini Linux Arm32 e Arm64.

Per altre informazioni, vedere ReadyToRun.

Runtime/SDK

Roll forward del runtime della versione principale

.NET core 3.0 introduce una funzionalità con consenso esplicito che consente all'app di eseguire il roll forward alla versione principale più recente di NET Core. È stata aggiunta anche una nuova impostazione per controllare come applicare il roll forward all'app. Questa funzionalità può essere configurata nei modi seguenti:

  • Proprietà file di progetto: RollForward
  • Proprietà file di configurazione runtime: rollForward
  • Variabile di ambiente: DOTNET_ROLL_FORWARD
  • Argomento della riga di comando: --roll-forward

È necessario specificare uno dei valori seguenti. Se non viene impostato un valore, l'impostazione Minor sarà quella predefinita.

  • LatestPatch
    Esegue il roll forward alla versione di patch più recente. Disabilita il roll forward della versione secondaria.
  • Minor
    Esegue il roll forward alla versione secondaria successiva minima, se la versione secondaria richiesta non esiste. Se la versione secondaria richiesta è presente, viene usato il criterio LatestPatch.
  • Major
    Esegue il roll forward alla versione principale successiva minima e alla versione secondaria minima, se la versione principale richiesta non esiste. Se la versione principale richiesta è presente, viene usato il criterio Minor.
  • LatestMinor
    Esegue il roll forward alla versione secondaria più recente, anche se la versione secondaria richiesta è presente. È destinata a scenari di hosting dei componenti.
  • LatestMajor
    Esegue il roll forward alla versione principale e secondaria più recente, anche se la versione principale richiesta è presente. È destinata a scenari di hosting dei componenti.
  • Disabilita
    Non esegue il roll forward. Esegue solo un'associazione alla versione specificata. Non è consigliato usare questo criterio per scopi generali poiché disabilita la possibilità di eseguire il roll forward alle patch più recenti. Questo valore è consigliato solo a scopo di test.

Ad eccezione dell'impostazione Disable, tutte le impostazioni useranno la versione di patch disponibile più recente.

Per impostazione predefinita, se la versione richiesta (come specificato in .runtimeconfig.json per l'applicazione) è una versione di rilascio, vengono considerate solo le versioni di rilascio per il roll forward. Tutte le versioni non definitive vengono ignorate. Se non è disponibile alcuna versione di rilascio corrispondente, vengono prese in considerazione le versioni non definitive. Questo comportamento può essere modificato impostando DOTNET_ROLL_FORWARD_TO_PRERELEASE=1, nel qual caso vengono sempre considerate tutte le versioni.

Copia delle dipendenze tramite la compilazione

Il comando dotnet build ora copia le dipendenze NuGet per l'applicazione dalla cache NuGet nella cartella di output per la compilazione. In precedenza, le dipendenze venivano copiate solo come parte di dotnet publish.

Esistono alcune operazioni, ad esempio il taglio e la pubblicazione della pagina razor, che richiedono comunque la pubblicazione.

Strumenti locali

.NET core 3.0 introduce gli strumenti locali. Gli strumenti locali sono simili agli strumenti globali, ma sono associati a una determinata posizione sul disco. Gli strumenti locali non sono disponibili a livello globale e vengono distribuiti come pacchetti NuGet.

Gli strumenti locali si basano sul nome file manifesto dotnet-tools.json nella directory corrente. Questo file manifesto definisce gli strumenti che devono essere disponibili in tale cartella e relative sottocartelle. È possibile distribuire il file manifesto con il codice per assicurarsi che tutti gli utenti che usano il codice possano ripristinare e usare gli stessi strumenti.

Per gli strumenti sia locali che globali, è necessaria una versione compatibile del runtime. Molti strumenti attualmente presenti su NuGet.org hanno come destinazione .NET Core Runtime 2.1. Per installare questi strumenti a livello globale o locale, è comunque necessario installare il runtime di NET Core 2.1.

Nuove opzioni global.json

Il file global.json offre nuove opzioni che garantiscono una maggiore flessibilità quando si tenta di definire quale versione di .NET Core SDK usare. Le nuove opzioni sono:

  • allowPrerelease: indica se il resolver SDK deve prendere in considerazione le versioni non definitive quando seleziona la versione dell'SDK da usare.
  • rollForward: indica i criteri di roll forward da usare quando si seleziona una versione dell'SDK, sia come fallback quando manca una versione specifica dell'SDK, sia come direttiva per usare una versione successiva.

Per altre informazioni sulle modifiche, inclusi i valori predefiniti, i valori supportati e le nuove regole di corrispondenza, vedere lapanoramica di global.json.

Riduzione delle dimensioni heap del Garbage Collector

Le dimensioni heap predefinite del Garbage Collector sono state ridotte tanto che .NET Core usa ora meno memoria. Questa modifica consente un migliore allineamento del budget di allocazione di generazione 0 con le dimensioni della cache dei processori moderni.

Supporto per pagine grandi in Garbage Collection

Le pagine di grandi dimensioni, dette anche huge page in Linux, consentono al sistema operativo di creare aree di memoria più grandi rispetto alle dimensioni di pagina native (spesso 4K). In questo modo si migliorano le prestazioni dell'applicazione che richiede pagine di grandi dimensioni.

Il Garbage Collector può ora essere configurato con l'impostazione GCLargePages come funzionalità con consenso esplicito per scegliere di allocare le pagine di grandi dimensioni in Windows.

Desktop di Windows e COM

Programma di installazione .NET Core SDK per Windows

Il programma di installazione di Windows Installer (MSI) per Windows è stato modificato a partire da .NET Core 3.0. I programmi di installazione di SDK aggiorneranno ora le versioni della banda di funzionalità sul posto. Le bande di funzionalità vengono definite nei gruppi centinaia nella sezione patch del numero di versione. Ad esempio, 3.0.101 e 3.0.201 sono versioni in due diverse bande di funzionalità, mentre 3.0.101 e 3.0.199 appartengono alla stessa banda. Quindi, quando viene installato .NET Core SDK 3.0.101, .NET Core SDK 3.0.100 verrà rimosso dal computer se è esistente. Quando viene installato .NET Core SDK 3.0.200 nello stesso computer, .NET Core SDK 3.0.101 non verrà rimosso.

Per altre informazioni sul controllo delle versioni, vedere Panoramica di come viene specificata la versione di .NET Core.

Desktop di Windows

.NET Core 3.0 supporta applicazioni desktop di Windows che usano Windows Forms e WPF (Windows Presentation Foundation). Questi framework supportano anche l'uso di controlli moderni e dello stile Fluent dalla libreria XAML dell'interfaccia utente di Windows tramite isole XAML.

Il componente Windows Desktop fa parte di Windows .NET Core 3.0 SDK.

È possibile creare una nuova app WPF o Windows Form con i comandi dotnet seguenti:

dotnet new wpf
dotnet new winforms

Visual Studio 2019 aggiunge modelli Nuovo progetto per .NET Core 3.0 Windows Forms e WPF.

Per altre informazioni su come convertire un'applicazione .NET Framework esistente, vedere Convertire progetti WPF e Convertire progetti Windows Forms.

Modalità con valori DPI alti per WinForms

Le applicazioni di Windows Forms in .NET Core possono impostare la modalità con valori DPI alti usando Application.SetHighDpiMode(HighDpiMode). Il metodo SetHighDpiMode imposta la modalità con valori DPI alti corrispondente a meno che l'impostazione sia stata configurata in altro modo, ad esempio con App.Manifest o P/Invoke prima di Application.Run.

I valori possibili per highDpiMode, espressi dall'enumerazione System.Windows.Forms.HighDpiMode, sono i seguenti:

  • DpiUnaware
  • SystemAware
  • PerMonitor
  • PerMonitorV2
  • DpiUnawareGdiScaled

Per altre informazioni sulle modalità con valori DPI alti, vedere Sviluppo di applicazioni desktop con valori DPI alti in Windows.

Creare componenti COM

In Windows è ora possibile creare componenti gestiti COM-Callable. Questa funzionalità è essenziale per usare .NET Core con modelli del componente aggiuntivo COM e anche per assicurare parità con .NET Framework.

A differenza di .NET Framework in cui mscoree.dll era usato come server COM, .NET Core aggiungerà un file dll di avvio nativo alla directory bin quando si compilerà il componente COM.

Per un esempio su come creare e usare un componente COM, vedere la demo COM.

Interoperabilità nativa di Windows

Windows offre un'API nativa completa, sotto forma di API C semplici, COM e WinRT. Mentre .NET Core supporta P/Invoke, .NET Core 3.0 aggiunge la possibilità di generare contestualmente API COM e di attivare API WinRT. Per un esempio di codice, vedere la demo Excel.

Distribuzione MSIX

MSIX è un nuovo formato di pacchetto di applicazioni Windows. Può essere usato per distribuire applicazioni desktop di .NET Core 3.0 in Windows 10.

Il Progetto di creazione pacchetti di applicazione Windows, disponibile in Visual Studio 2019, consente di creare pacchetti MSIX con applicazioni .NET Core autonome.

Il file di progetto .NET Core deve specificare i runtime supportati nella proprietà <RuntimeIdentifiers>:

<RuntimeIdentifiers>win-x86;win-x64</RuntimeIdentifiers>

Miglioramenti di Linux

SerialPort per Linux

.NET Core 3.0 include il supporto di base per System.IO.Ports.SerialPort in Linux.

In precedenza, .NET Core supportava solo l'uso di SerialPort in Windows.

Per altre informazioni sul supporto limitato per la porta seriale in Linux, vedere il problema 33146 su GitHub.

Docker e limiti di memoria cgroup

L'esecuzione di .NET Core 3.0 in Linux con Docker funziona meglio con i limiti di memoria cgroup. Eseguendo un contenitore Docker con limiti di memoria, ad esempio docker run -m, il comportamento di .NET Core cambia.

  • Dimensioni heap predefinite del Garbage Collector: massimo 20 MB o il 75% del limite di memoria nel contenitore.
  • È possibile impostare dimensioni esplicite come numero assoluto o percentuale di un limite cgroup.
  • Le dimensioni minime del segmento riservato per ogni heap del Garbage Collection sono pari a 16 MB. Le dimensioni riducono il numero di heap creati nei computer.

Supporto di GPIO per Raspberry Pi

Sono stati rilasciati due pacchetti NuGet che è possibile usare per la programmazione GPIO:

I pacchetti GPIO includono le API per i dispositivi GPIO, SPI, I2C e PWM. Il pacchetto di binding IoT include i binding di dispositivi. Per altre informazioni, vedere il repository GitHub dei dispositivi.

Supporto Arm64 per Linux

.NET Core 3.0 aggiunge il supporto Arm64 per Linux. Il caso d'uso principale per Arm64 è attualmente con gli scenari IoT. Per altre informazioni, vedere Stato di .NET Core Arm64.

Sono disponibili immagini Docker per .NET Core in Arm64 per Alpine, Debian e Ubuntu.

Nota

Il supporto per i sistemi operativi macOS Arm64 (o "Apple Silicon") e Windows Arm64 è stato aggiunto successivamente in .NET 6.

Sicurezza

TLS 1.3 e OpenSSL 1.1.1 in Linux

.NET Core sfrutta ora il supporto di TLS 1.3 in OpenSSL 1.1.1, quando è disponibile in un determinato ambiente. Con TLS 1.3:

  • La durata della connessione è migliorata grazie alla riduzione del numero di round trip necessari tra il client e il server.
  • La sicurezza è migliorata grazie alla rimozione di vari algoritmi di crittografia obsoleti e non sicuri.

Quando è disponibile, .NET Core 3.0 usa OpenSSL 1.1.1, OpenSSL 1.1.0 o OpenSSL 1.0.2 in un sistema Linux. Quando OpenSSL 1.1.1 è disponibile, entrambi i tipi System.Net.Security.SslStream e System.Net.Http.HttpClient useranno TLS 1.3, supponendo che sia il client sia il server supportino TLS 1.3.

L'esempio seguente di C# 8.0 illustra .NET Core 3.0 in Ubuntu 18.10 che si connette a https://www.cloudflare.com:

using System;
using System.Net.Security;
using System.Net.Sockets;
using System.Threading.Tasks;

namespace whats_new
{
    public static class TLS
    {
        public static async Task ConnectCloudFlare()
        {
            var targetHost = "www.cloudflare.com";

            using TcpClient tcpClient = new TcpClient();

            await tcpClient.ConnectAsync(targetHost, 443);

            using SslStream sslStream = new SslStream(tcpClient.GetStream());

            await sslStream.AuthenticateAsClientAsync(targetHost);
            await Console.Out.WriteLineAsync($"Connected to {targetHost} with {sslStream.SslProtocol}");
        }
    }
}

Crittografia

.NET Core 3.0 aggiunge il supporto per le crittografie AES-GCM e AES-CCM, implementate rispettivamente con System.Security.Cryptography.AesGcm e System.Security.Cryptography.AesCcm. Sono entrambi algoritmi di cifratura autenticata con dati di associazione.

Il codice seguente illustra l'uso della crittografia AesGcm per crittografare e decrittografare dati casuali.

using System;
using System.Linq;
using System.Security.Cryptography;

namespace whats_new
{
    public static class Cipher
    {
        public static void Run()
        {
            // key should be: pre-known, derived, or transported via another channel, such as RSA encryption
            byte[] key = new byte[16];
            RandomNumberGenerator.Fill(key);

            byte[] nonce = new byte[12];
            RandomNumberGenerator.Fill(nonce);

            // normally this would be your data
            byte[] dataToEncrypt = new byte[1234];
            byte[] associatedData = new byte[333];
            RandomNumberGenerator.Fill(dataToEncrypt);
            RandomNumberGenerator.Fill(associatedData);

            // these will be filled during the encryption
            byte[] tag = new byte[16];
            byte[] ciphertext = new byte[dataToEncrypt.Length];

            using (AesGcm aesGcm = new AesGcm(key))
            {
                aesGcm.Encrypt(nonce, dataToEncrypt, ciphertext, tag, associatedData);
            }

            // tag, nonce, ciphertext, associatedData should be sent to the other part

            byte[] decryptedData = new byte[ciphertext.Length];

            using (AesGcm aesGcm = new AesGcm(key))
            {
                aesGcm.Decrypt(nonce, ciphertext, tag, decryptedData, associatedData);
            }

            // do something with the data
            // this should always print that data is the same
            Console.WriteLine($"AES-GCM: Decrypted data is {(dataToEncrypt.SequenceEqual(decryptedData) ? "the same as" : "different than")} original data.");
        }
    }
}

Importazione/Esportazione di chiavi crittografiche

.NET core 3.0 supporta l'importazione e l'esportazione di chiavi pubbliche e private asimmetriche da formati standard. Non è necessario usare un certificato X.509.

Tutti i tipi di chiave, ad esempio RSA, DSA, ECDsa e ECDiffieHellman, supportano i formati seguenti:

  • Chiave pubblica

    • X.509 SubjectPublicKeyInfo
  • Chiave privata

    • PKCS#8 PrivateKeyInfo
    • PKCS#8 EncryptedPrivateKeyInfo

Le chiavi RSA supportano anche i tipi seguenti:

  • Chiave pubblica

    • PKCS#1 RSAPublicKey
  • Chiave privata

    • PKCS#1 RSAPrivateKey

I metodi di esportazione generano dati binari con codifica DER e i metodi di importazione prevedono lo stesso tipo di comportamento. Se una chiave viene archiviata nel formato PEM per il testo, il chiamante dovrà applicare la decodifica Base 64 al contenuto prima di chiamare un metodo di importazione.

using System;
using System.Security.Cryptography;

namespace whats_new
{
    public static class RSATest
    {
        public static void Run(string keyFile)
        {
            using var rsa = RSA.Create();

            byte[] keyBytes = System.IO.File.ReadAllBytes(keyFile);
            rsa.ImportRSAPrivateKey(keyBytes, out int bytesRead);

            Console.WriteLine($"Read {bytesRead} bytes, {keyBytes.Length - bytesRead} extra byte(s) in file.");
            RSAParameters rsaParameters = rsa.ExportParameters(true);
            Console.WriteLine(BitConverter.ToString(rsaParameters.D));
        }
    }
}

I file PKCS#8 possono essere esaminati con la classe System.Security.Cryptography.Pkcs.Pkcs8PrivateKeyInfo e i file PFX/PKCS#12 possono essere esaminati con la classe System.Security.Cryptography.Pkcs.Pkcs12Info. I file PFX/PKCS#12 possono essere modificati con la classe System.Security.Cryptography.Pkcs.Pkcs12Builder.

Modifiche dell'API .NET Core 3.0

Gli intervalli e indici

Il nuovo tipo System.Index può essere usato per l'indicizzazione. È possibile crearne uno da int, che esegue il conteggio dall'inizio, o con un operatore prefisso ^ (C#), che esegue il conteggio dalla fine:

Index i1 = 3;  // number 3 from beginning
Index i2 = ^4; // number 4 from end
int[] a = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Console.WriteLine($"{a[i1]}, {a[i2]}"); // "3, 6"

Esiste anche il tipo System.Range, costituito da due valori Index, uno per l'inizio e uno per la fine, e può essere scritto con un'espressione intervallo x..y (C#). È anche possibile poi indicizzare usano un oggetto Range, che genera una sezione:

var slice = a[i1..i2]; // { 3, 4, 5 }

Per altre informazioni, vedere l'esercitazione su intervalli e indici.

Flussi asincroni

Il tipo IAsyncEnumerable<T> è una nuova versione asincrona di IEnumerable<T>. Il linguaggio consente di usare await foreach su IAsyncEnumerable<T> per utilizzarne gli elementi e di usare yield return per generare gli elementi.

L'esempio seguente illustra sia la produzione che l'utilizzo dei flussi asincroni. L'istruzione foreach è asincrona e usa yield return per produrre un flusso asincrono per i chiamanti. Questo modello (con yield return) è quello consigliato per la produzione di flussi asincroni.

async IAsyncEnumerable<int> GetBigResultsAsync()
{
    await foreach (var result in GetResultsAsync())
    {
        if (result > 20) yield return result;
    }
}

Oltre a poter usare await foreach, è anche possibile creare iteratori asincroni, ad esempio un iteratore che restituisce IAsyncEnumerable/IAsyncEnumerator in cui è possibile usare sia await che yield. Per gli oggetti che devono essere eliminati, è possibile usare IAsyncDisposable, implementato da diversi tipi BCL, ad esempio Stream e Timer.

Per altre informazioni, vedere l'esercitazione sui flussi asincroni.

Virgola mobile IEEE

È in corso l'aggiornamento di API virgola mobile per conformità alla revisione IEEE 754-2008. L'obiettivo di queste modifiche è esporre tutte le operazioni obbligatorie e assicurarsi che, a livello di comportamento, siano conformi alla specifica IEEE. Per altre informazioni sui miglioramenti di virgola mobile, vedere il post di blog Floating-Point Parsing and Formatting improvements in .NET Core 3.0 (Miglioramenti di analisi e formattazione di virgola mobile in .NET Core 3.0).

Di seguito sono riportate le correzioni per analisi e formattazione:

  • Analisi corretta e arrotondamento degli input di qualsiasi lunghezza.
  • Analisi corretta e formattazione dello zero negativo.
  • Analisi corretta di valori Infinity e NaN con l'esecuzione di un controllo senza distinzione tra maiuscole e minuscole e consentendo un + precedente facoltativo, ove applicabile.

Le nuovi API System.Math includono gli elementi seguenti:

  • BitIncrement(Double) e BitDecrement(Double)
    Corrispondono alle operazioni IEEE nextUp e nextDown. Restituiscono il numero a virgola mobile più piccolo che risulta maggiore o minore rispetto all'input (rispettivamente). Ad esempio, Math.BitIncrement(0.0) restituirebbe double.Epsilon.

  • MaxMagnitude(Double, Double) e MinMagnitude(Double, Double)
    Corrispondono alle operazioni IEEE maxNumMag e minNumMag e restituiscono il valore maggiore o minore in termini di grandezza dei due input (rispettivamente). Ad esempio, Math.MaxMagnitude(2.0, -3.0) restituirebbe -3.0.

  • ILogB(Double)
    Corrispondono all'operazione IEEE logB che restituisce un valore integrale, restituisce il logaritmo in base 2 integrale del parametro di input. Questo metodo equivale in effetti a floor(log2(x)), ma con errori minimi di arrotondamento.

  • ScaleB(Double, Int32)
    Corrisponde all'operazione IEEE scaleB che accetta un valore integrale, restituisce in effetti x * pow(2, n), ma con errori minimi di arrotondamento.

  • Log2(Double)
    Corrisponde all'operazione IEEE log2 e restituisce il logaritmo in base 2. Gli errori di arrotondamento sono ridotti al minimo.

  • FusedMultiplyAdd(Double, Double, Double)
    Corrisponde all'operazione IEEE fma ed esegue un'operazione FMA (Fused Multiply-Add). Vale a dire, esegue (x * y) + z come una singola operazione, riducendo così al minimo gli errori di arrotondamento. Un esempio è FusedMultiplyAdd(1e308, 2.0, -1e308), che restituisce 1e308. L'operazione normale (1e308 * 2.0) - 1e308 restituisce double.PositiveInfinity.

  • CopySign(Double, Double)
    Corrisponde all'operazione IEEE copySign e restituisce il valore di x, ma con il segno di y.

Intrinseci dipendenti dalla piattaforma .NET

Sono state aggiunte API che consentono l'accesso a determinate istruzioni CPU orientate alle prestazioni, ad esempio i set di istruzioni SIMD oppure di istruzioni di manipolazione dei bit. Queste istruzioni consentono di ottenere miglioramenti delle prestazioni significativi in determinati scenari, ad esempio l'elaborazione dei dati in modo efficiente in parallelo.

Ove appropriato, le librerie .NET hanno iniziato a usare queste istruzioni per migliorare le prestazioni.

Per altre informazioni, vedere Intrinseci dipendenti dalla piattaforma .NET.

Miglioramento delle API della versione .NET Core

A partire da .NET Core 3.0, le API della versione di .NET Core restituiscono le informazioni previste. Ad esempio:

System.Console.WriteLine($"Environment.Version: {System.Environment.Version}");

// Old result
//   Environment.Version: 4.0.30319.42000
//
// New result
//   Environment.Version: 3.0.0
System.Console.WriteLine($"RuntimeInformation.FrameworkDescription: {System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription}");

// Old result
//   RuntimeInformation.FrameworkDescription: .NET Core 4.6.27415.71
//
// New result (notice the value includes any preview release information)
//   RuntimeInformation.FrameworkDescription: .NET Core 3.0.0-preview4-27615-11

Avviso

Modifica importante. si tratta di una modifica tecnicamente importante perché è cambiato lo schema di controllo delle versioni.

Supporto JSON predefinito rapido

Gli utenti .NET si sono ampiamente basati su Newtonsoft.Json e altre librerie JSON molto diffuse, che rimangono sempre scelte valide. Newtonsoft.Json usa le stringhe .NET come tipo di dati di base, che in realtà sono UTF-16.

Il nuovo supporto JSON predefinito offre prestazioni elevate, bassa allocazione e funziona con il testo JSON codificato in UTF-8. Per altre informazioni sullo System.Text.Jsonspazio dei nomi e sui tipi, vedere gli articoli seguenti:

Supporto HTTP/2

Il tipo System.Net.Http.HttpClient supporta il protocollo HTTP/2. Se HTTP/2 è abilitato, la versione del protocollo HTTP viene negoziata tramite TLS/ALPN e HTTP/2 viene usato solo in base alla decisione del server.

Il protocollo predefinito rimane HTTP/1.1, anche se HTTP/2 può essere abilitato in due modi diversi. In primo luogo, è possibile impostare il messaggio di richiesta HTTP per usare HTTP/2:

var client = new HttpClient() { BaseAddress = new Uri("https://localhost:5001") };

// HTTP/1.1 request
using (var response = await client.GetAsync("/"))
    Console.WriteLine(response.Content);

// HTTP/2 request
using (var request = new HttpRequestMessage(HttpMethod.Get, "/") { Version = new Version(2, 0) })
using (var response = await client.SendAsync(request))
    Console.WriteLine(response.Content);

In secondo luogo, è possibile modificare HttpClient in modo da usare HTTP/2 per impostazione predefinita:

var client = new HttpClient()
{
    BaseAddress = new Uri("https://localhost:5001"),
    DefaultRequestVersion = new Version(2, 0)
};

// HTTP/2 is default
using (var response = await client.GetAsync("/"))
    Console.WriteLine(response.Content);

Molto spesso, quando si sviluppa un'applicazione, si vuole usare una connessione non crittografata. Se si è a conoscenza del fatto che l'endpoint di destinazione userà HTTP/2, è possibile attivare connessioni non crittografate per HTTP/2. Per attivare queste connessioni è possibile impostare la variabile di ambiente DOTNET_SYSTEM_NET_HTTP_SOCKETSHTTPHANDLER_HTTP2UNENCRYPTEDSUPPORT su 1 o abilitarla nel contesto dell'app:

AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);

Passaggi successivi