Esercitazione: Introduzione a Funzioni & di Azure Visual Studio per Mac
Si applica a: Visual Studio per Mac
Visual Studio
In questa esercitazione si apprenderà come iniziare a creare le funzioni di Azure tramite Visual Studio per Mac. Si eseguirà anche l'integrazione con le tabelle di archiviazione di Azure, uno dei vari tipi di binding e trigger disponibili per gli sviluppatori di funzioni di Azure.
Obiettivi
- Creare ed eseguire il debug di funzioni di Azure locali
- Integrare risorse di archiviazione Web e di Azure
- Gestire un flusso di lavoro che interessa più funzioni di Azure
Requisiti
- Visual Studio per Mac 7.5 o versione successiva.
- Sottoscrizione di Azure (disponibile gratuitamente in https://azure.com/free).
Esercizio 1: Creazione di un progetto di Funzioni di Azure
Avviare Visual Studio per Mac.
Selezionare Nuova soluzione file>.
Nella categoria Cloud > Generale selezionare il modello Funzioni di Azure . Si userà C# per creare una libreria di classi .NET che ospita le funzioni di Azure. Fare clic su Avanti.
Impostare Nome progetto su "AzureFunctionsLab" e fare clic su Crea.
Espandere i nodi nella finestra della soluzione. Il modello di progetto predefinito include riferimenti NuGet a vari pacchetti di Processi Web di Azure e al pacchetto Newtonsoft.Json.
Sono anche disponibili tre file: host.json per la descrizione delle opzioni di configurazione globale per l'host, local.settings.json per la configurazione delle impostazioni del servizio. - Il modello di progetto crea anche un HttpTrigger predefinito. Ai fini di questa esercitazione, eliminare il file HttpTrigger.cs dal progetto.
Aprire local.settings.json. Per impostazione predefinita il file include due impostazioni stringa di connessione vuote.
Esercizio 2: Creazione di un account di archiviazione di Azure
Accedere al proprio account Azure in https://portal.azure.com.
Nella sezione Preferiti sul lato sinistro dello schermo, selezionare Account di archiviazione:
Selezionare Aggiungi per creare un nuovo account di archiviazione:
Immettere un nome univoco a livello globale in Nome e riusarlo per Gruppo di risorse. Mantenere i valori predefiniti per tutti gli altri elementi.
Fare clic su Crea. La creazione dell'account di archiviazione può richiedere alcuni minuti. Al completamento si riceve una notifica.
Selezionare il pulsante Vai alla risorsa nella notifica.
Selezionare la scheda Chiavi di accesso.
Copiare la prima stringa di connessione. Questa stringa viene usata in seguito per integrare l'archiviazione di Azure con Funzioni di Azure.
Tornare a Visual Studio per Mac e incollare la stringa di connessione completa nell'impostazione AzureWebJobsStorage in local.settings.json. Ora è possibile fare riferimento al nome dell'impostazione negli attributi per le funzioni che richiedono l'accesso alle risorse dell'impostazione.
Esempio 3: Creazione e debug di una funzione di Azure
Ora è possibile iniziare ad aggiungere codice. Quando si usa una libreria di classi .NET le funzioni di Azure vengono aggiunte come metodi statici. Nella finestra della soluzione fare clic con il pulsante destro del mouse sul nodo del progetto AzureFunctions e scegliere Aggiungi > funzione:
Nella finestra di dialogo Nuova funzione di Azure selezionare il modello webhook generico. Impostare Nome su Add e fare clic su Ok per creare una funzione:
Nella parte superiore del nuovo file aggiungere le direttive using seguenti:
using Microsoft.Azure.WebJobs.Extensions.Http; using System.Web; using Microsoft.WindowsAzure.Storage.Table;
Rimuovere il metodo
Run
esistente e aggiungere il metodo seguente alla classe come funzione di Azure:[FunctionName("Add")] public static int Run( [HttpTrigger(AuthorizationLevel.Function, "get", Route = null)] HttpRequestMessage req, TraceWriter log) { int x = 1; int y = 2; return x + y; }
Di seguito si analizzano in dettaglio le varie sezioni della definizione del metodo.
Inizialmente viene visualizzato l'attributo FunctionName, che contrassegna questo metodo come funzione di Azure. L'attributo specifica il nome pubblico della funzione. Il nome dell'attributo non deve necessariamente corrispondere al nome del metodo.
Successivamente, il metodo è contrassegnato come metodo public static, impostazione necessaria. Si noterà anche che il valore restituito è un int. A meno che non venga specificato in caso contrario, il valore restituito non void di una funzione di Azure viene restituito al client come testo. Per impostazione predefinita viene restituito come XML, ma può essere modificato in JSON. Si eseguirà questa operazione più avanti nell'esercitazione.
Il primo parametro è contrassegnato con l'attributo HttpTrigger, che indica che il metodo viene chiamato da una richiesta HTTP. L'attributo specifica anche il livello di autorizzazione del metodo, nonché i verbi supportati (in questo caso solo "GET"). È anche possibile definire una Route che sostituisce il percorso del metodo e consente di estrarre automaticamente variabili dal percorso. Dato che in questo caso l'impostazione Route è null, il percorso di questo metodo assume l'impostazione predefinita /api/Add.
Il parametro finale del metodo è un TraceWriter che può essere usato per registrare messaggi per errori e di diagnostica.
Impostare un punto di interruzione sulla riga return del metodo facendo clic sul margine della riga:
Compilare ed eseguire il progetto in una sessione di debug premendo F5 o selezionando Esegui > debug start. In alternativa è possibile scegliere pulsante Esegui. Tutte queste opzioni eseguono la stessa attività. Nel resto di questa esercitazione viene citato F5, ma è possibile usare il metodo che si preferisce.
Quando si esegue il progetto, viene aperta automaticamente l'applicazione Terminale.
Il progetto esegue un processo di rilevamento delle funzioni di Azure in base agli attributi del metodo e a una convenzione di file illustrata più avanti in questo articolo. In questo caso rileva una sola funzione di Azure e "genera" una funzione del processo.
Nella parte inferiore dei messaggi di avvio, l'host Funzioni di Azure visualizza gli URL delle eventuali API trigger HTTP. Dovrebbe essere presente un solo trigger. Copiare l'URL e incollarlo in una nuova scheda del browser.
Il punto di interruzione viene attivato immediatamente. La richiesta Web è stata inoltrata alla funzione e ora può essere sottoposta a debug. Portare il mouse sulla variabile x per visualizzarne il valore.
Rimuovere il punto di interruzione con lo stesso metodo usato in precedenza per aggiungerlo (fare clic sul margine o selezionare la riga e premere F9).
Premere F5 per continuare l'esecuzione.
Nel browser viene visualizzato il risultato XML del metodo. Come previsto, l'operazione di addizione hardcoded produce una somma plausibile. Nota, se viene visualizzato solo "3" in Safari, passare a Preferenze >> Safari Avanzate e selezionare la casella di controllo "Mostra menu sviluppo nella barra dei menu" e ricaricare la pagina.
In Visual Studio per Mac fare clic sul pulsante Arresta per terminare la sessione di debug. Per garantire che le nuove modifiche vengano implementate, ricordare di riavviare (arrestare e quindi eseguire) la sessione di debug.
Nel metodo Run sostituire le definizioni x e y con il codice seguente. Questo codice estrae valori dalla stringa di query dell'URL, per far sì che l'operazione di addizione sia eseguibile in modo dinamico in base ai parametri specificati.
var query = HttpUtility.ParseQueryString(req.RequestUri.Query); int x = int.Parse(query["x"]); int y = int.Parse(query["y"]); return x + y;
Eseguire l'applicazione.
Tornare alla finestra del browser e aggiungere la stringa
/?x=2&y=3
all'URL. L'URL intero ora saràhttp://localhost:7071/api/Add?x=2&y=3
. Passare al nuovo URL.Ora il risultato rifletterà i nuovi parametri. Eseguire il progetto con valori diversi. Non è disponibile nessun controllo degli errori, pertanto in caso di parametri non validi o mancanti viene generato un errore.
Arrestare la sessione di debug.
Esercizio 4: Uso di function.json
In un esercizio precedente, si indicava che Visual Studio per Mac "generava" una funzione di processo per la funzione di Azure definita nella libreria. Questo accade perché Funzioni di Azure non usa gli attributi del metodo in fase di runtime, ma usa una convenzione di file system in fase di compilazione per configurare la posizione e la modalità con cui le funzioni di Azure vengono rese disponibili. Nella finestra della soluzione fare clic con il pulsante destro del mouse sul nodo del progetto e selezionare Reveal in Finder.
Spostarsi verso il basso nel file system fino a raggiungere bin/Debug/netstandard2.0. Trovare la cartella Add. La cartella è stata creata per la corrispondenza con l'attributo del nome di funzione nel codice C#. Espandere la cartella Add per visualizzare un singolo file function.json. Questo file viene usato dal runtime per ospitare e gestire la funzione di Azure. Per altri modelli di linguaggio senza supporto in fase di compilazione (ad esempio script C# o JavaScript), queste cartelle devono essere create e gestite manualmente. Per gli sviluppatori C# vengono generate automaticamente dai metadati degli attributi in fase di compilazione. Fare clic con il pulsante destro del mouse su function.json e selezionare l'opzione che lo apre in Visual Studio.
Tenendo in considerazione le fasi precedenti dell'esercitazione, ora si avrà un'idea di base degli attributi C#. Di conseguenza questo codice JSON dovrebbe risultare familiare. Tuttavia alcuni elementi non sono stati illustrati negli esercizi precedenti. Ad esempio, per ogni binding deve essere impostato l'elemento direction corrispondente. Come si può dedurre, "in" indica che il parametro è di input, mentre "out" indica che il parametro è un valore restituito (tramite $return) o un parametro out per il metodo. È anche necessario specificare l'elemento scriptFile (relativo a questo percorso finale) e il metodo entryPoint (public e static) all'interno dell'assembly. Nei passaggi seguenti si aggiungerà un percorso di funzione personalizzato usando questo modello. Copiare il contenuto di questo file negli Appunti.
Nella finestra della soluzione fare clic con il pulsante destro del mouse sul nodo del progetto AzureFunctionsLab e scegliere Aggiungi > nuova cartella. Assegnare il nome Adder alla nuova cartella. Per convenzione predefinita, il nome di questa cartella definisce il percorso dell'API, ad esempio api/Adder.
Fare clic con il pulsante destro del mouse sulla cartella Adder e scegliere Aggiungi > nuovo file.
Selezionare la categoria Web e il modello File JSON vuoto. Impostare Nome su function e fare clic su Nuovo.
Incollare il contenuto dell'altro file function.json (ottenuto nel passaggio 3) per sostituire il contenuto predefinito del file appena creato.
Rimuovere le righe seguenti dalla parte iniziale del file con estensione json:
"configurationSource":"attributes", "generatedBy":"Microsoft.NET.Sdk.Functions-1.0.13",
Alla fine del primo binding (dopo la riga "name": "req") aggiungere le proprietà seguenti. Non dimenticare di includere una virgola nella riga precedente. Questa proprietà sostituisce la radice predefinita e ora estrae i parametri int dal percorso e li inserisce nei parametri del metodo denominati x e y.
"direction": "in", "route": "Adder/{x:int?}/{y:int?}"
Aggiungere un altro binding sotto il primo. Questo binding gestisce il valore restituito della funzione. Non dimenticare di includere una virgola nella riga precedente:
{ "name": "$return", "type": "http", "direction": "out" }
Aggiornare anche la proprietà entryPoint nella parte inferiore del file in modo che usi un metodo chiamato "Add2", come indicato di seguito. Lo scopo è dimostrare che il percorso api/Adder... può eseguire il mapping a un metodo appropriato con qualsiasi nome (in questo caso Add2).
"entryPoint": "<project-name>.<function-class-name>.Add2"
Il file function.json finale avrà un aspetto simile al seguente:
{ "bindings": [ { "type": "httpTrigger", "methods": [ "get" ], "authLevel": "function", "direction": "in", "name": "req", "route": "Adder/{x:int?}/{y:int?}" }, { "name": "$return", "type": "http", "direction": "out" } ], "disabled": false, "scriptFile": "../bin/AzureFunctionsProject.dll", "entryPoint": "AzureFunctionsProject.Add.Add2" }
Il passaggio finale necessario per attivare il funzionamento del progetto è un'istruzione che richiede a Visual Studio per Mac di copiare il file nello stesso percorso relativo della directory di output ogni volta che viene modificato. Con il file selezionato, scegliere la scheda delle proprietà sulla barra a destra, quindi in Copia nella directory di output selezionare Copia se più recente:
In Add.cs sostituire il metodo
Run
(incluso l'attributo) con il metodo seguente per completare la funzione prevista. Il metodo è molto simile aRun
, ma non usa attributi e dispone di parametri espliciti per x e y.public static int Add2( HttpRequestMessage req, int x, int y, TraceWriter log) { return x + y; }
Premere F5 per compilare ed eseguire il progetto.
Dopo il completamento della compilazione e l'avvio della piattaforma, questa indica che è disponibile una seconda route per le richieste, mappata sul metodo appena aggiunto:
Tornare alla finestra del browser e passare a http://localhost:7071/api/Adder/3/5.
Ora il metodo funziona di nuovo ed estrae parametri dal percorso, quindi produce una somma.
Tornare a Visual Studio per Mac e terminare la sessione di debug.
Esercizio 5: Uso delle tabelle di archiviazione di Azure
Spesso il servizio compilato è molto più complesso di quello creato fino a questo punto e la sua esecuzione può richiedere un'infrastruttura e tempi molto maggiori. In questi casi può risultare utile accettare le richieste che vengono messe in coda per l'elaborazione quando le risorse diventano disponibili. Le funzioni di Azure supportano questo approccio. In altri casi risulta più utile archiviare i dati in modo centralizzato. Le tabelle di Archiviazione di Azure consentono di eseguire questa operazione rapidamente.
Aggiungere la classe seguente a Add.cs. La classe deve essere inserita all'interno dello spazio dei nomi, ma all'esterno della classe esistente.
public class TableRow : TableEntity { public int X { get; set; } public int Y { get; set; } public int Sum { get; set; } }
Nella classe Add aggiungere il codice seguente per introdurre un'altra funzione. Si noti che fino a questo punto il codice è univoco, in quanto non prevede una risposta HTTP. La riga finale restituisce un nuovo elemento TableRow completo di alcuni dati chiave che ne faciliteranno il recupero in una fase successiva (PartitionKey e RowKey), nonché dei relativi parametri e della somma. Anche il codice all'interno del metodo usa TraceWriter per facilitare il rilevamento dell'esecuzione della funzione.
[FunctionName("Process")] [return: Table("Results")] public static TableRow Process( [HttpTrigger(AuthorizationLevel.Function, "get", Route = "Process/{x:int}/{y:int}")] HttpRequestMessage req, int x, int y, TraceWriter log) { log.Info($"Processing {x} + {y}"); return new TableRow() { PartitionKey = "sums", RowKey = $"{x}_{y}", X = x, Y = y, Sum = x + y }; }
Premere F5 per compilare ed eseguire il progetto.
Nella scheda del browser, passare a http://localhost:7071/api/Process/4/6. Questa operazione inserisce un altro messaggio nella coda, che a sua volta aggiungerà un'altra riga alla tabella in un secondo momento.
Tornare a Terminal e verificare la richiesta in ingresso per 4 + 6.
Tornare al browser per aggiornare la richiesta con lo stesso URL. Questa volta verrà visualizzato un errore dopo il metodo Process. Questo avviene perché il codice prova ad aggiungere una riga alla tabella di Archiviazione tabelle di Azure tramite una combinazione di partizione e chiave riga che esiste già.
System.Private.CoreLib: Exception while executing function: Process. Microsoft.Azure.WebJobs.Host: Error while handling parameter $return after function returned:. Microsoft.Azure.WebJobs.Host: The specified entity already exists.
Arrestare la sessione di debug.
Per correggere l'errore, aggiungere il parametro seguente alla definizione del metodo, immediatamente prima del parametro TraceWriter. Questo parametro richiede alla piattaforma Funzioni di Azure di provare il recupero di una TableRow dalla tabella Results per la PartitionKey usata per l'archiviazione dei risultati. Tuttavia sarà sorprendente notare che RowKey viene generata dinamicamente in base agli altri parametri x e y per lo stesso metodo. Se tale riga esiste già, tableRow la includerà quando inizia l'esecuzione del metodo, senza richiedere lavoro aggiuntivo allo sviluppatore. Se la riga non esiste, il valore sarà null. Questo tipo di efficienza consente agli sviluppatori di concentrarsi sulla logica di business importante anziché sull'infrastruttura.
[Table("Results", "sums", "{x}_{y}")] TableRow tableRow,
Aggiungere il codice seguente all'inizio del metodo. Se tableRow non è null, i risultati per l'operazione richiesta sono già disponibili e possono essere restituiti immediatamente. In caso contrario, l'esecuzione della funzione continua come in precedenza. Questo potrebbe non essere il modo più efficiente per restituire i dati, ma dimostra che è possibile organizzare operazioni molto sofisticate su più livelli scalabili con un volume di codice molto ridotto.
if (tableRow != null) { log.Info($"{x} + {y} already exists"); return null; }
Premere F5 per compilare ed eseguire il progetto.
Nella scheda del browser, aggiornare l'URL in http://localhost:7071/api/Process/4/6. Dato che la riga della tabella per questo record esiste, viene restituita immediatamente e senza errori. Poiché non esiste alcun output HTTP, è possibile visualizzare l'output nel Terminale.
Aggiornare l'URL in modo da riflettere una combinazione non ancora sottoposta a test, ad esempio http://localhost:7071/api/Process/5/7. Si noti il messaggio nel Terminale, indicante che la riga della tabella non è stata trovata (come previsto).
Tornare a Visual Studio per Mac e terminare la sessione di debug.
Riepilogo
In questa esercitazione si è appreso come iniziare a creare le funzioni di Azure tramite Visual Studio per Mac.