Condividi su:

The chosen one: .NET 5

.NET 5, il successore di .NET Core 3.1 e .NET Framework 4.8, mira a fornire agli sviluppatori .NET una nuova esperienza di sviluppo multipiattaforma. Mette ordine alla frammentazione dell’universo .NET che si è verificata nel corso degli anni e apporta nuove straordinarie funzionalità. Di seguito i cinque punti su cui concentrarci per capire agevolmente quali sono i punti di forza dell’ultima release per gli sviluppatori di casa Microsoft.

1. Piattaforma Unificata

La prima cosa che c’è da sapere è che .NET 5 offre una nuova visione unificata del mondo .NET.

Se abbiamo già lavorato con .NET, dovremmo essere a conoscenza della sua frammentazione di piattaforme sin dalla sua prima versione nel 2002. .NET Framework è stato inizialmente progettato per Windows, ma la sua specifica di runtime, nota anche come Common Language Infrastructure (CLI), fu standardizzata come ECMA 335.

Questa standardizzazione consentì a chiunque di creare la propria implementazione del runtime .NET. Infatti non si attese molto per veder comparirne i primi all’orizzonte: abbiamo Mono per sistemi basati su Linux, Silverlight per applicazioni basate su browser, framework .NET Compact e Micro per dispositivi mobili e con risorse limitate e così via.

Per questi motivi, Microsoft decise di scrivere .NET Core da zero pensando esclusivamente alla compatibilità multipiattaforma. Queste diverse implementazioni hanno sollevato la necessità di capire “dove” potrebbe essere eseguito un pacchetto .NET.

Dovresti creare versioni diverse della tua libreria per distribuirla? La risposta a questa domanda fu .NET Standard, ovvero una specifica formale delle API comuni che dovresti aspettarti tra le implementazioni della CLI. In altre parole, se crei la tua libreria per uno specifico .NET Standard, avrai la garanzia che verrà eseguita su tutti i runtime che implementano tale specifica.

Si comprende dunque che, in questa situazione disordinata, la compatibilità di implementazione desiderata non era così facile da ottenere. Questo è il motivo per cui .NET 5 appare in scena.

La nuova piattaforma .NET è il successore unificato delle varie versioni .NET: .NET Framework, .NET Standard, .NET Core, Mono, ecc. È ufficialmente la prossima versione di .NET Core 3.1, ma sostanzialmente determina la fine di .NET Framework, .NET Standard e le altre varianti che hanno causato grossi grattacapi agli sviluppatori .NET.

.NET 5 fornisce un set comune di API che allinea le diverse implementazioni di runtime. Questo set di API è identificato dal Net5.0 Target Framework Moniker (TFM), che è il token impostato nel progetto .NET per specificare il framework di destinazione. Ciò consente l’esecuzione dell’applicazione su qualsiasi implementazione di runtime che supporta .NET 5. Tuttavia, è comunque possibile compilare applicazioni per una piattaforma specifica. Ad esempio, per creare un’applicazione che utilizza l’API di Windows, è necessario specificare il TFM net5.0-windows. In questo modo, la creazione di un’applicazione specifica per la piattaforma è una tua scelta, non una scelta che dipende dall’implementazione di runtime che stai utilizzando per sviluppare la tua applicazione.

Naturalmente, realizzare questa piattaforma unificata ha richiesto uno sforzo significativo e una riorganizzazione dell’architettura interna. Alcune funzionalità sono state rimosse dal set di API di base, come vedrai più avanti, ma la piattaforma ha ottenuto un miglioramento generale delle prestazioni.

Mentre il nuovo .NET 5 viene fornito con l’obiettivo di unificazione della piattaforma, il piano iniziale è cambiato a causa del COVID-19. In effetti, .NET 5 pone le basi dell’unificazione, ma sarà completato con .NET 6 a novembre 2021. Con tale rilascio, otterremo la versione stabile della nuova Universal UI ed anche il supporto per i TFM specifici per Android ( net6.0-android) e iOS (net6.0-ios).

2. Nuove funzionalità in C#

La seconda cosa da tenere a mente riguarda C#. .NET 5 include C# 9, la nuova versione del principale linguaggio di programmazione della piattaforma .NET. Ci sono diverse nuove funzionalità, e di seguito ne troveremo un piccolissimo assaggio, giusto per farci “venir fame”.

Dichiarazioni Top-Level

Tra le nuove funzionalità, una delle più notevoli è l’introduzione di dichiarazioni top-level (o di primo livello). Per sapere cosa sono, diamo un’occhiata al seguente programma:

Ebbene, il precedente blocco potrà essere tranquillamente sostituito dal semplice ed unico:

Le istruzioni top-level consentono di concentrarsi su ciò che conta davvero in piccoli programmi e utilità per console e utilizzare C# con un approccio più orientato agli script.

Tipi di record

Un’altra interessante novità sono i tipi di record. Con i record, possiamo dichiarare un tipo di riferimento immutabile, ovvero un tipo basato sulla classe che non può essere modificato dopo la sua creazione. Un esempio di tipo di riferimento immutabile incorporato è la classe System.String. Dopo aver creato un’istanza di System.String, non è più possibile modificarne il valore.

Considera la seguente dichiarazione del tipo di record:

Possiamo creare un istanza del record Person come faremmo per una classe, ma non ne possiamo alterare ad esempio la proprietà FirstName.

Potremo comunque confrontare due istanze del record Person come si trattassero di tipologie primitive:

Init setters

C# 9 aggiunge anche la funzione di init setters per definire proprietà che possono essere solo inizializzate. Consideriamo la seguente definizione di classe:

Questa classe definisce una persona con proprietà LastName e FirstName che possono essere inizializzate, ma non modificate. La proprietà Address può essere invece modificata in qualsiasi momento:

3. .NET MAUI, the Universal UI

Come terzo punto, dobbiamo sapere che .NET 5 offre un nuovo modo di creare interfacce utente multipiattaforma. Grazie al framework UI dell’app multipiattaforma .NET, noto anche come .NET MAUI, saremo in grado di creare interfacce utente per Android, iOS, macOS e Windows con un unico progetto.

In realtà, questa funzionalità è ancora in corso e verrà rilasciata con .NET 6, ma possiamo iniziare a dare un’occhiata a .NET MAUI per essere pronto quando verrà rilasciato ufficialmente fin dal .NET 5.

.NET MAUI può essere considerato un’evoluzione di Xamarin.Forms, il framework open source per la creazione di app iOS e Android con un’unica base di codice .NET. Ma questo nuovo framework propone un modello universale per la creazione di interfacce utente su piattaforme mobili e desktop.

.NET MAUI

Oltre al buon vecchio Model-View-ViewModel (MVVM) pattern, .NET MAUI supporta anche il recentissimo Model-View-Update (MVU).

4. Supporto Single-File Applications

Altra grande feature che otterremo in .NET 5 è il supporto alle single-file applications, ovvero applicazioni pubblicate e distribuite come un singolo file. Ciò significa che la nostra applicazione e tutte le sue dipendenze sono raggruppate in un unico file.

Ad esempio, supponiamo di eseguire il seguente comando all’interno della cartella del nostro progetto .NET 5:

Otterremo un singolo file contenente l’intera applicazione creata per Linux, tutte le dipendenze usate nel  progetto ed il runtime .NET (–self-contained true). Ciò significa che non è nemmeno necessario installare il runtime .NET sul computer/server di destinazione.

Naturalmente, si potranno specificare questi parametri nella configurazione del progetto:

Notate bene che questa funzionalità non usa lo stesso approccio delle applicazioni a file singolo che puoi compilare in .NET Core 3.1. In .NET Core 3.1. L’applicazione a file singolo è solo un modo per creare pacchetti binari: in fase di esecuzione vengono poi scompattati in una cartella temporanea, caricati ed eseguiti. In .NET 5, l’applicazione a file singolo ha una nuova struttura interna e viene eseguita direttamente senza penalizzazioni delle prestazioni.

A questo link è possibile trovare la documentazione di questa tipologia di rilascio.

5. Tecnologie non più supportate

Per ultimo punto, è obbligo parlare anche di chi esce dal ciclo delle tecnologie supportate, non solo dei nuovi arrivati.

Come detto sopra, la revisione dell’architettura e il tentativo di rendere .NET 5 un vero e proprio framework di programmazione multipiattaforma ha portato alla rimozione di alcune funzionalità supportate in .NET Framework. Diamo una rapida occhiata alle funzionalità rimosse e alle possibili alternative.

Web Forms

Per molto tempo, ASP.NET Web Forms è stata la principale tecnologia per creare interfacce utente web dinamiche. Tuttavia, non è un segreto che la sua durata fosse strettamente legata al destino di .NET Framework. .NET Core non supporta Web Form, quindi il fatto che non sia più supportato in .NET 5 non dovrebbe essere una grande novità.

Tuttavia, abbiamo alcune alternative per creare interfacce utente web. Se stiamo realizzando applicazioni web tradizionali, Razor Pages è una di queste alternative. Se vuoi creare applicazioni a pagina singola, puoi usare invece Blazor.

Windows Communication Foundation (WCF)

Anche WCF, il framework di comunicazione tradizionale per Windows, sarà deprecato. Questo può sembrare un po’ scioccante per gli sviluppatori che lo hanno utilizzato per creare le loro applicazioni orientate ai servizi. Tuttavia, è abbastanza comprensibile se ci rendiamo conto che l’obiettivo principale di .NET 5 è diventare un framework multipiattaforma.

L’alternativa a WCF consigliata da Microsoft è la migrazione a gRPC. Ma se abbiamo nostalgia di WCF o vuoi preparare una transizione graduale, puoi provare il progetto open source CoreWCF.

Windows Workflow Foundation

Infine, .NET 5 non includerà nemmeno Windows Workflow Foundation, la tecnologia del motore del flusso di lavoro disponibile in .NET Framework. Non esiste un sostituto ufficiale per questa tecnologia. Tuttavia, potremo usare un progetto di porting open source, CoreWF, per tentare di spostare i flussi di lavoro esistenti su .NET 5 o crearne di nuovi.

Primi Passi Insieme

Nella seconda parte di questo articolo sperimenteremo insieme la creazione di un nuovo progetto web tramite Visual Studio sfruttando il framework .NET 5 e mettendo subito alla prova il suo aspetto multipiattaforma, pubblicandolo su di una macchina Linux (Ubuntu).

Non temiate la lunghezza della scrollbar verticale del vostro browser, la guida è stata resa il più user-friendly possibile riportando intere porzioni di codice e schermate dei “punti salienti”, ecco spiegato il motivo della sua lunghezza.

Creiamo il nuovo progetto con Visual Studio

Creiamo il nuovo progetto cross platform “MyCrossPlatformApp” partendo dal template “ASP.NET Core Web App”. Se non si trova il suddetto template tra quelli disponibili, assicurarsi di aver selezionato la voce “All platforms” e soprattutto che sia installata sul vostro Visual Studio la relativa SDK.

NB! E’ essenziale selezionare come Target Framework -> .NET 5

Una volta completato lo scaffolding del nuovo progetto possiamo tranquillamente procedere con la sua pubblicazione.

Non sono necessarie ulteriori modifiche essendo il nostro obiettivo ultimo l’esecuzione del progetto su una macchina Linux. Possiamo comunque provare a far partire il progetto per assicurarci che non contenga errori (e che Visual Studio non stia tentando di nascosto di sabotarci…).

Il risultato sarà la classica pagina di benvenuto del template selezionato.

Eradicati i nostri dubbi riguardo la bontà della compilazione del progetto, possiamo finalmente pubblicarlo.

Il risultato della pubblicazione sarà una cartella contenente exe, dll e files di configurazione del nostro applicativo, compilati per il rilascio sulla nostra piattaforma desiderata.

Procediamo dunque cliccando col destro sulla nostra soluzione nell’explorer di Visual Studio e selezionado la voce Publish.

Questo avvierà il wizard di creazione di un nuovo Profilo di Pubblicazione.

Delle varie modalità di pubblicazione, sceglieremo la più grezza e legacy, ovvero la pubblicazione su cartella/folder. In questo modo, lasciando tutte le impostazioni di default proposte nella successiva schermata, avremo il nostro risultato nella sotto cartella di progetto bin\Release\net5.0\publish .

Una volta creato il nuovo profilo di pubblicazione possiamo procedere cliccando dapprima su Publish (1) ed in seguito esaminando il risultato cliccando sulla cartella di output (2).

Et voilà! Una volta terminata la pubblicazione su cartella possiamo chiudere con Visual Studio ed iniziare a dedicarci alla nostra macchina Linux. Essendo il progetto compilato con un framework multipiattaforma (.NET5), nella cartella bin\Release\net5.0\publish avremo tutto il necessario per far partire l’app su qualsiasi Sistema Operativo in cui è installabile la relativa runtime.

Di seguito procederemo con la pubblicazione sull’ultima versione server Debian e l’ultima versione long-term support di Ubuntu Server.

UBUNTU 20.04 LTS &  Apache

Prerequisiti

  1. Salvo particolarissime eccezioni o esigenze, sarebbe ideale cominciare a riscaldarci sul terminale con la solita sfilza di formalismi necessari a partire con tutti i repositori e pacchetti aggiornati:
    1. sudo apt-get update
    1. sudo apt-get upgrade
    1. sudo apt-get dist-upgrade
    1. sudo apt-get autoclean
    1. sudo apt-get autoremove

  2. Nonostante sia un appunto banale e per molti scontato, tengo a precisare che per trasferire il nostro progetto sul server Ubuntu in questa guida faremo uso del protocollo SFTP. Sarà dunque necessario installare sulla macchina in questione la versione server di SSH (se non già presente) con il comando:
    1. sudo apt-get install openssh-server

Step#1 – Installazione Runtimes

Per prima cosa dobbiamo assicurarci che siano installate le runtime di .NET5 e ASP.NET Core 5. Procediamo con il seguente comando per listarle tutte:

dotnet –list-runtimes

Se il risultato dovesse essere il seguente (“command not found”) allora dobbiamo fare un passetto indietro, installandone almeno una.

Installare le runtime .NET non è complicato.
come già visto per l’SSH, possiamo tranquillamente procedere con la loro installazione tramite il packet manager di Ubuntu apt:

  • Runtime .NET5
    sudo apt-get install dotnet-runtime-5.0
  • Runtime ASP.NET Core 5
    sudo apt-get install aspnetcore-runtime-5.0

Con gran probabilità, arrivati a questo punto vi scontrerete con la mancanza dei pacchetti dotnet-runtime-5.0 e aspnetcore-runtime-5.0 negli attuali repository della vostra macchina, come da screen di seguito (“Unable to locate package (…)”) .

Non disperate: oltre alla guida ufficiale Microsoft per l’aggiunta del repository (LINK) potrete nuovamente fare affidamento a quanto segue di questa guida. Infatti, per l’aggiunta dei repository ufficiali Microsoft sul nostro server Ubuntu basterà eseguire i seguenti comandi:

curl -sSL https://packages.microsoft.com/keys/microsoft.asc | sudo tee /etc/apt/trusted.gpg.d/microsoft.asc
sudo apt-add-repository https://packages.microsoft.com/ubuntu/20.04/prod
sudo apt-get update

A questo punto saremo in grado di ritentare con successo l’installazione delle runtime .NET come descritto poche righe addietro, assicurandoci infine che compaiano nella lista fornita dal comando:

dotnet –list-runtimes

Step#2 – Installazione & Config. Apache

Dobbiamo sapere che le applicazioni .Net vengono eseguite su server Kestrel. Il nostro web server Apache fungerà da server proxy e gestirà il traffico dall’esterno della macchina reindirizzandolo al server Kestrel. Possiamo dunque vedere il nostro web server Apache come un middle layer per l’applicazione .Net .

Di seguito vedremo come installare e configurare un’installazione pulita di Apache sul nostro server Ubuntu per servire la nostra applicazione.

Diamo quindi i seguenti comando per installare Apache ed abilitare in seconda battutati i moduli proxy,proxy_http, proxy_html e proxy_wstunnel.

sudo apt-get install apache2
sudo a2enmod proxy proxy_http proxy_html proxy_wstunnel
sudo a2enmod rewrite
systemctl restart apache2

Possiamo confermare la corretta installazione di Apache navigando con un browser all’indirizzo del nostro server. Se tutto è andato liscio, il risultato sarà la pagina di default di Apache con tanto di messaggio evidenziato IT WORKS come da screen:

Arrivati a questo punto,dovremo creare un file conf per configurare il nostro proxy su Apache.
Forniamo dunque il seguente comando per entrare nell’editor di testo nano :

sudo nano /etc/apache2/conf-enabled/netcore.conf

Copiamo ora la seguente configurazione nel file vuoto appena aperto per poi salvarlo con la combinazione (per chi non la conoscesse) CTRL+O -> INVIO -> CTRL+X .

NB! La porta 5000 è quella usata di default dal server Kestrel con cui si eseguono le applicazioni .Net

<VirtualHost *:80> 
   ServerName localhost 
   ProxyPreserveHost On 
   ProxyPass / http://127.0.0.1:5000/
   ProxyPassReverse / http://127.0.0.1:5000/ 
   RewriteEngine on 
   RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC] 
   RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC] 
   RewriteRule /(.*) ws://127.0.0.1:5000/$1 [P] 
   ErrorLog /var/log/apache2/netcore-error.log 
   CustomLog /var/log/apache2/netcore-access.log common 
</VirtualHost>

Ora con il seguente comando ci assicuriamo che non siano presenti errori nella configurazione appena create su Apache:

sudo apachectl configtest

A prescindere dai vari warning segnati, se riceviamo infine il messaggio Syntax OK possiamo procedere con il riavvio di Apache:

sudo service apache2 restart

Effettuando nuovamente la navigazione con un browser puntando all’indirizzo della nostra macchina, ci accorgeremo di non avere più la pagina di default di Apache esposta, bensì un messaggio di Service Unavailable . Risultato del tutto normale poiché Apache sta già funzionando da server proxy, mirando in realtà alla porta 5000 della macchina sulla quale non è ancora stata avviata la nostra applicazione .Net con Kestrel.

Step#3 – Spostamento Progetto & Creazione Servizio

E’ giunto ora il momento di riversare il nostro progetto compilato sul nostro server Linux.

Come anticipato nelle premesse di questa guida, uno degli strumenti più comodi per chi lavora su una macchina Windows è WinSCP, con il quale potremo trasferire files tramite SFTP.

Prima di spostare i files, sarebbe utile creare preventivamente la cartella di destinazione del progetto, che nel nostro caso si chiamerà MyCrossPlatformApp e sarà nella home della mia utenza cerini.

cd /home/cerini
mkdir MyCrossPlatformApp

Ecco che una volta connessi con WinSCP potremo spostare comodamente il progetto nella cartella appena creata anche con un semplice Drag&Drop.

Possiamo finalmente testare il corretto funzionamento della nostra soluzione cross platform e della bontà della configurazione del reverse proxy di Apache avviando l’applicazione e facendo di conseguenza partire il server Kestrel sulla porta 5000 col comando:

dotnet MyCrossPlatformApp.dll

Visitando nuovamente col browser la nostra macchina, il messaggio di “Service Unavailable” sarà soltanto un lontano ricordo.

Rimane soltanto un ultimo “problema”:
l’esecuzione dell’applicazione è contestualizzata all’istanza di terminale che ha lanciato il comando dot, dunque fin quando non ne termineremo l’esecuzione con la combinazione di comandi CTRL+C, l’istanza di questo terminale sarà occupata da questo unico job, impedendoci di usarla per qualsiasi altro task.

E’ qui che entrano in gioco i service di Ubuntu. Un service (o servizio se preferite in italiano) su Ubuntu costituisce la gestione regolarizzata di uno o più processi in totale autonomia dell’OS ed in background.

Tra i vari parametri configurabili di un servizio, troviamo quelli che ne definiscono il tempo di esecuzione, partenza e comportamento in caso di errore, come ad esempio il riavvio od un nuovo tentativo ad una certa distanza temporale.

I servizi su Ubuntu sono facilmente gestibili con il comando service o il suo sinonimo systemctl, fornendo come parametro l’operazione da effettuare sul servizio specificato:enalbe, disable, stop, start, restart e status.

Creiamo dunque il file di configurazione per il servizio che si occuperà di avviare (e tenere avviata) la nostra applicazione .NET sul server.
Come in precedenza, usiamo l’editor nano per creare il suddetto file:

sudo nano /etc/systemd/system/MyCrossPlatformApp.service

Avviato l’editor del nuovo file vuoto, possiamo copiare al suo interno la seguente configurazione, salvandola infine con CTRL+O -> INVIO -> CTRL+X :

[Unit]

Description=ASP .NET Web Application

[Service]

WorkingDirectory=/home/cerini/MyCrossPlatformApp

ExecStart=/usr/bin/dotnet /home/cerini/MyCrossPlatformApp/ MyCrossPlatformApp.dll

Restart=always

# Restart service after 10 seconds if the dotnet service crashes:

RestartSec=10

SyslogIdentifier=dotnet5-demo

User=www-data

Environment=ASPNETCORE_ENVIRONMENT=Production

[Install]

WantedBy=multi-user.target


Tra le config più interessanti troviamo la WorkingDirectory con cui diamo il contesto della cartella di esecuzione, ExecStart che definisce il vero e proprio comando da eseguire (dotnet + dll), Restart e RestartSec con cui definiamo il comportamento in caso di errore/crash del servizio.

Possiamo dunque abilitare il servizio e tentarne l’avvio:

sudo systemctl enable MyCrossPlatformApp

sudo systemctl start MyCrossPlatformAppt

Controlliamo infine che sia correttamente partito con:

sudo systemctl status MyCrossPlatformApp

La prova del nove la potrete tranquillamente avere navigando come al solito dal vostro browser.

Provare per credere! E se vi sentite fortunati (e ne avete la possibilità) provate a riavviare il vostro server: il servizio avvierà la vostra applicazione .NET automaticamente una volta ripartito Ubuntu.

Articolo a cura di Luca Cerini, Senior Developer in Orbyta Tech, 07/09/2021

#jointherevolution