Connettere Funzioni di Azure ad Archiviazione di Azure con gli strumenti da riga di comando
In questo articolo si integra una coda di Archiviazione di Azure con la funzione e l'account di archiviazione creati nell'argomento di avvio rapido precedente. È possibile ottenere questa integrazione usando un binding di output che scrive i dati di una richiesta HTTP in un messaggio della coda. Il completamento di questo articolo non comporta costi aggiuntivi oltre ai pochi centesimi di dollaro USA dell'argomento di avvio rapido precedente. Per altre informazioni sui binding, vedere Concetti su trigger e binding di Funzioni di Azure.
Configurare l'ambiente locale
Prima di iniziare, è necessario completare l'articolo Avvio rapido: Creare un progetto Funzioni di Azure dalla riga di comando. Se è già stata eseguita la pulizia delle risorse alla fine di tale articolo, eseguire di nuovo i passaggi per ricreare l'app per le funzioni e le risorse correlate in Azure.
Prima di iniziare, è necessario completare l'articolo Avvio rapido: Creare un progetto Funzioni di Azure dalla riga di comando. Se è già stata eseguita la pulizia delle risorse alla fine di tale articolo, eseguire di nuovo i passaggi per ricreare l'app per le funzioni e le risorse correlate in Azure.
Prima di iniziare, è necessario completare l'articolo Avvio rapido: Creare un progetto Funzioni di Azure dalla riga di comando. Se è già stata eseguita la pulizia delle risorse alla fine di tale articolo, eseguire di nuovo i passaggi per ricreare l'app per le funzioni e le risorse correlate in Azure.
Prima di iniziare, è necessario completare l'articolo Avvio rapido: Creare un progetto Funzioni di Azure dalla riga di comando. Se è già stata eseguita la pulizia delle risorse alla fine di tale articolo, eseguire di nuovo i passaggi per ricreare l'app per le funzioni e le risorse correlate in Azure.
Prima di iniziare, è necessario completare l'articolo Avvio rapido: Creare un progetto Funzioni di Azure dalla riga di comando. Se è già stata eseguita la pulizia delle risorse alla fine di tale articolo, eseguire di nuovo i passaggi per ricreare l'app per le funzioni e le risorse correlate in Azure.
Prima di iniziare, è necessario completare l'articolo Avvio rapido: Creare un progetto Funzioni di Azure dalla riga di comando. Se è già stata eseguita la pulizia delle risorse alla fine di tale articolo, eseguire di nuovo i passaggi per ricreare l'app per le funzioni e le risorse correlate in Azure.
Recuperare la stringa di connessione di Archiviazione di Azure
In precedenza è stato creato un account Archiviazione di Azure per l'uso dell'app per le funzioni. La stringa di connessione per questo account è archiviata in modo sicuro nelle impostazioni dell'app in Azure. Scaricando l'impostazione nel file local.settings.json , è possibile usare la connessione per scrivere in una coda di archiviazione nello stesso account quando si esegue la funzione in locale.
Dalla radice del progetto eseguire il comando seguente, sostituire
<APP_NAME>
con il nome dell'app per le funzioni del passaggio precedente. Questo comando sovrascrive tutti i valori esistenti nel file.func azure functionapp fetch-app-settings <APP_NAME>
Aprire local.settings.json file e individuare il valore denominato
AzureWebJobsStorage
, ovvero l'account di archiviazione stringa di connessione. Il nomeAzureWebJobsStorage
e la stringa di connessione si usano in altre sezioni di questo articolo.
Importante
Poiché il file local.settings.json contiene segreti scaricati da Azure, escludere sempre questo file dal controllo del codice sorgente. Il file con estensione gitignore creato con un progetto di funzioni locale esclude il file per impostazione predefinita.
Registrare le estensioni delle associazioni
Ad eccezione dei trigger HTTP e timer, i binding vengono implementati come pacchetti di estensione. Eseguire il comando dotnet add package seguente nella finestra del terminale per aggiungere il pacchetto di estensione di archiviazione nel progetto.
dotnet add package Microsoft.Azure.Functions.Worker.Extensions.Storage.Queues --prerelease
Ora è possibile aggiungere il binding di output di archiviazione nel progetto.
Aggiungere una definizione di binding di output alla funzione
Anche se una funzione può avere un solo trigger, può avere più associazioni di input e output, che consente di connettersi ad altri servizi e risorse di Azure senza scrivere codice di integrazione personalizzato.
Quando si usa il modello di programmazione Node.js v4, gli attributi di associazione vengono definiti direttamente nel file ./src/functions/HttpExample.js . Nell'argomento di avvio rapido precedente il file contiene già un'associazione HTTP definita dal app.http
metodo .
const { app } = require('@azure/functions');
app.http('httpTrigger', {
methods: ['GET', 'POST'],
authLevel: 'anonymous',
handler: async (request, context) => {
try {
context.log(`Http function processed request for url "${request.url}"`);
const name = request.query.get('name') || (await request.text());
context.log(`Name: ${name}`);
if (!name) {
return { status: 404, body: 'Not Found' };
}
return { body: `Hello, ${name}!` };
} catch (error) {
context.log(`Error: ${error}`);
return { status: 500, body: 'Internal Server Error' };
}
},
});
Quando si usa il modello di programmazione Node.js v4, gli attributi di associazione vengono definiti direttamente nel file ./src/functions/HttpExample.js . Nell'argomento di avvio rapido precedente il file contiene già un'associazione HTTP definita dal app.http
metodo .
import {
app,
HttpRequest,
HttpResponseInit,
InvocationContext,
} from '@azure/functions';
export async function httpTrigger1(
request: HttpRequest,
context: InvocationContext,
): Promise<HttpResponseInit> {
context.log(`Http function processed request for url "${request.url}"`);
const name = request.query.get('name') || (await request.text()) || 'world';
return { body: `Hello, ${name}!` };
}
app.http('httpTrigger1', {
methods: ['GET', 'POST'],
authLevel: 'anonymous',
handler: httpTrigger1,
});
Questi binding vengono dichiarati nel file function.json nella cartella della funzione. Dall'argomento di avvio rapido precedente il file function.json nella cartella HttpExample contiene due binding nella raccolta bindings
:
Quando si usa il modello di programmazione Python v2, gli attributi di associazione vengono definiti direttamente nel file function_app.py come elementi decorator. Nell'argomento di avvio rapido precedente il file di function_app.py contiene già un'associazione basata su decorator:
import azure.functions as func
import logging
app = func.FunctionApp()
@app.function_name(name="HttpTrigger1")
@app.route(route="hello", auth_level=func.AuthLevel.ANONYMOUS)
L'elemento decorator aggiunge l'associazione route
HttpTrigger e HttpOutput alla funzione, che consente l'attivazione della funzione quando le richieste HTTP raggiungono la route specificata.
Per scrivere in una coda Archiviazione di Azure da questa funzione, aggiungere l'elemento queue_output
Decorator al codice della funzione:
@app.queue_output(arg_name="msg", queue_name="outqueue", connection="AzureWebJobsStorage")
Nell'elemento decorator arg_name
identifica il parametro di associazione a cui si fa riferimento nel codice, queue_name
è il nome della coda in cui scrive l'associazione e connection
è il nome di un'impostazione dell'applicazione che contiene il stringa di connessione per l'account di archiviazione. Negli argomenti di avvio rapido si usa lo stesso account di archiviazione dell'app per le funzioni, che si trova nell'impostazione AzureWebJobsStorage
(da local.settings.json file). Se queue_name
non esiste, il binding lo crea al primo utilizzo.
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "Request",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "Response"
}
]
Per scrivere in una coda dell'account di archiviazione di Azure:
Aggiungere una proprietà
extraOutputs
alla configurazione dell'associazione{ methods: ['GET', 'POST'], extraOutputs: [sendToQueue], // add output binding to HTTP trigger authLevel: 'anonymous', handler: () => {} }
Aggiungere una funzione
output.storageQueue
sopra la chiamataapp.http
const sendToQueue: StorageQueueOutput = output.storageQueue({ queueName: 'outqueue', connection: 'AzureWebJobsStorage', });
Il secondo binding nella raccolta è denominato res
. Questo binding http
è un binding di output (out
) usato per scrivere la risposta HTTP.
Per scrivere in una coda di Archiviazione di Azure da questa funzione, aggiungere un binding out
di tipo queue
con il nome msg
, come illustrato nel codice seguente:
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "Request",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "Response"
},
{
"type": "queue",
"direction": "out",
"name": "msg",
"queueName": "outqueue",
"connection": "AzureWebJobsStorage"
}
]
}
Per un queue
tipo, è necessario specificare il nome della coda in queueName
e specificare il nome della connessione Archiviazione di Azure (da local.settings.json file) in connection
.
In un progetto C# i binding vengono definiti come attributi di binding nel metodo della funzione. Definizioni specifiche dipendono dal fatto che l'app venga eseguita in-process (libreria di classi C#) o in un processo di lavoro isolato.
Aprire il file di progetto HttpExample.cs e aggiungere la classe seguente MultiResponse
:
public class MultiResponse
{
[QueueOutput("outqueue",Connection = "AzureWebJobsStorage")]
public string[] Messages { get; set; }
public HttpResponseData HttpResponse { get; set; }
}
La classe MultiResponse
consente di scrivere in una coda di archiviazione denominata outqueue
e in un messaggio HTTP riuscito. È possibile inviare più messaggi alla coda perché l'attributo QueueOutput
viene applicato a una matrice di stringhe.
La proprietà Connection
imposta la stringa di connessione per l'account di archiviazione. In questo caso, è possibile omettere Connection
, perché si usa già l'account di archiviazione predefinito.
In un progetto Java i binding vengono definiti come annotazioni di binding nel metodo della funzione. Il file function.json viene quindi generato automaticamente in base a queste annotazioni.
Passare al percorso del codice della funzione, src/main/java, aprire il file di progetto Function.java e aggiungere il parametro seguente alla definizione del metodo run
:
@QueueOutput(name = "msg", queueName = "outqueue", connection = "AzureWebJobsStorage") OutputBinding<String> msg
Il msg
parametro è un OutputBinding<T>
tipo, che rappresenta una raccolta di stringhe. Queste stringhe vengono scritte come messaggi in un'associazione di output al termine della funzione. In questo caso, l'output è una coda di archiviazione denominata outqueue
. La stringa di connessione per l'account di archiviazione è impostata dal metodo connection
. Passare l'impostazione dell'applicazione che contiene l'account di archiviazione stringa di connessione, anziché passare il stringa di connessione stesso.
La definizione del run
metodo deve ora essere simile all'esempio seguente:
@FunctionName("HttpTrigger-Java")
public HttpResponseMessage run(
@HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.FUNCTION)
HttpRequestMessage<Optional<String>> request,
@QueueOutput(name = "msg", queueName = "outqueue", connection = "AzureWebJobsStorage")
OutputBinding<String> msg, final ExecutionContext context) {
...
}
Per altre informazioni sui dettagli dei binding, vedere Concetti su trigger e binding di Funzioni di Azure e la configurazione dell'output della coda.
Aggiungere il codice per usare il binding di output
Una volta definita l'associazione della coda, è possibile aggiornare la funzione per ricevere il parametro di output msg
e scrivere i messaggi nella coda.
Aggiornare HttpExample\function_app.py in modo che corrisponda al codice seguente, aggiungendo il parametro msg
alla definizione della funzione e msg.set(name)
sotto l'istruzione if name:
:
import azure.functions as func
import logging
app = func.FunctionApp(http_auth_level=func.AuthLevel.ANONYMOUS)
@app.route(route="HttpExample")
@app.queue_output(arg_name="msg", queue_name="outqueue", connection="AzureWebJobsStorage")
def HttpExample(req: func.HttpRequest, msg: func.Out [func.QueueMessage]) -> func.HttpResponse:
logging.info('Python HTTP trigger function processed a request.')
name = req.params.get('name')
if not name:
try:
req_body = req.get_json()
except ValueError:
pass
else:
name = req_body.get('name')
if name:
msg.set(name)
return func.HttpResponse(f"Hello, {name}. This HTTP triggered function executed successfully.")
else:
return func.HttpResponse(
"This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response.",
status_code=200
)
Il parametro msg
è un'istanza della azure.functions.Out class
. Il metodo set
scrive un messaggio stringa nella coda. In questo caso, è il name
passato alla funzione nella stringa di query URL.
Aggiungere il codice che usa l'oggetto del binding di output in context.extraOutputs
per creare un messaggio della coda. Aggiungere questo codice prima dell'istruzione return.
context.extraOutputs.set(sendToQueue, [msg]);
A questo punto, la funzione potrebbe essere come indicato di seguito:
const { app, output } = require('@azure/functions');
const sendToQueue = output.storageQueue({
queueName: 'outqueue',
connection: 'AzureWebJobsStorage',
});
app.http('HttpExample', {
methods: ['GET', 'POST'],
authLevel: 'anonymous',
extraOutputs: [sendToQueue],
handler: async (request, context) => {
try {
context.log(`Http function processed request for url "${request.url}"`);
const name = request.query.get('name') || (await request.text());
context.log(`Name: ${name}`);
if (name) {
const msg = `Name passed to the function ${name}`;
context.extraOutputs.set(sendToQueue, [msg]);
return { body: msg };
} else {
context.log('Missing required data');
return { status: 404, body: 'Missing required data' };
}
} catch (error) {
context.log(`Error: ${error}`);
return { status: 500, body: 'Internal Server Error' };
}
},
});
Aggiungere il codice che usa l'oggetto del binding di output in context.extraOutputs
per creare un messaggio della coda. Aggiungere questo codice prima dell'istruzione return.
context.extraOutputs.set(sendToQueue, [msg]);
A questo punto, la funzione potrebbe essere come indicato di seguito:
import {
app,
output,
HttpRequest,
HttpResponseInit,
InvocationContext,
StorageQueueOutput,
} from '@azure/functions';
const sendToQueue: StorageQueueOutput = output.storageQueue({
queueName: 'outqueue',
connection: 'AzureWebJobsStorage',
});
export async function HttpExample(
request: HttpRequest,
context: InvocationContext,
): Promise<HttpResponseInit> {
try {
context.log(`Http function processed request for url "${request.url}"`);
const name = request.query.get('name') || (await request.text());
context.log(`Name: ${name}`);
if (name) {
const msg = `Name passed to the function ${name}`;
context.extraOutputs.set(sendToQueue, [msg]);
return { body: msg };
} else {
context.log('Missing required data');
return { status: 404, body: 'Missing required data' };
}
} catch (error) {
context.log(`Error: ${error}`);
return { status: 500, body: 'Internal Server Error' };
}
}
app.http('HttpExample', {
methods: ['GET', 'POST'],
authLevel: 'anonymous',
handler: HttpExample,
});
Aggiungere il codice che usa il cmdlet Push-OutputBinding
per scrivere un testo nella coda usando il binding di output msg
. Aggiungere questo codice prima di impostare lo stato OK nell'istruzione if
.
$outputMsg = $name
Push-OutputBinding -name msg -Value $outputMsg
A questo punto, la funzione deve essere come indicato di seguito:
using namespace System.Net
# Input bindings are passed in via param block.
param($Request, $TriggerMetadata)
# Write to the Azure Functions log stream.
Write-Host "PowerShell HTTP trigger function processed a request."
# Interact with query parameters or the body of the request.
$name = $Request.Query.Name
if (-not $name) {
$name = $Request.Body.Name
}
if ($name) {
# Write the $name value to the queue,
# which is the name passed to the function.
$outputMsg = $name
Push-OutputBinding -name msg -Value $outputMsg
$status = [HttpStatusCode]::OK
$body = "Hello $name"
}
else {
$status = [HttpStatusCode]::BadRequest
$body = "Please pass a name on the query string or in the request body."
}
# Associate values to output bindings by calling 'Push-OutputBinding'.
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
StatusCode = $status
Body = $body
})
Sostituire la classe HttpExample
esistente con il codice seguente:
[Function("HttpExample")]
public static MultiResponse Run([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req,
FunctionContext executionContext)
{
var logger = executionContext.GetLogger("HttpExample");
logger.LogInformation("C# HTTP trigger function processed a request.");
var message = "Welcome to Azure Functions!";
var response = req.CreateResponse(HttpStatusCode.OK);
response.Headers.Add("Content-Type", "text/plain; charset=utf-8");
response.WriteString(message);
// Return a response to both HTTP trigger and storage output binding.
return new MultiResponse()
{
// Write a single message.
Messages = new string[] { message },
HttpResponse = response
};
}
}
Ora è possibile usare il nuovo parametro msg
per scrivere nel binding di output dal codice della funzione. Aggiungere la riga di codice seguente prima della risposta di operazione riuscita per aggiungere il valore di name
al binding di output msg
.
msg.setValue(name);
Quando si usa un binding di output, non è necessario usare il codice di Azure Storage SDK per l'autenticazione, per recuperare un riferimento alla coda o per scrivere dati. Queste attività vengono eseguite automaticamente dal runtime di Funzioni e dal binding di output.
Il run
metodo deve ora essere simile all'esempio seguente:
public HttpResponseMessage run(
@HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS)
HttpRequestMessage<Optional<String>> request,
@QueueOutput(name = "msg", queueName = "outqueue",
connection = "AzureWebJobsStorage") OutputBinding<String> msg,
final ExecutionContext context) {
context.getLogger().info("Java HTTP trigger processed a request.");
// Parse query parameter
String query = request.getQueryParameters().get("name");
String name = request.getBody().orElse(query);
if (name == null) {
return request.createResponseBuilder(HttpStatus.BAD_REQUEST)
.body("Please pass a name on the query string or in the request body").build();
} else {
// Write the name to the message queue.
msg.setValue(name);
return request.createResponseBuilder(HttpStatus.OK).body("Hello, " + name).build();
}
}
Aggiornare i test
Poiché l'archetipo crea anche un set di test, è necessario aggiornare questi test per gestire il nuovo parametro msg
nella firma del metodo run
.
Passare al percorso del codice di test in src/test/java, aprire il file di progetto Function.java e sostituire la riga di codice in //Invoke
con il codice seguente:
@SuppressWarnings("unchecked")
final OutputBinding<String> msg = (OutputBinding<String>)mock(OutputBinding.class);
final HttpResponseMessage ret = new Function().run(req, msg, context);
Si noti che non è necessario scrivere codice per l'autenticazione, ottenendo un riferimento alla coda o scrivendo dati. Tutte queste attività di integrazione vengono gestite facilmente nel runtime di Funzioni di Azure e nel binding di output della coda.
Eseguire la funzione in locale
Eseguire la funzione avviando l'host di runtime locale di Funzioni di Azure nella cartella LocalFunctionProj.
func start
Verso la fine dell'output, devono essere visualizzate le righe seguenti:
Nota
Se HttpExample non viene visualizzato come illustrato sopra, è probabile che l'host non sia stato avviato dalla cartella radice del progetto. In tal caso, premere CTRL+C per arrestare l'host, andare alla cartella radice del progetto ed eseguire di nuovo il comando precedente.
Copiare l'URL della funzione HTTP da questo output in un browser e aggiungere la stringa di query
?name=<YOUR_NAME>
, rendendo l'URL completo comehttp://localhost:7071/api/HttpExample?name=Functions
. Il browser dovrebbe visualizzare un messaggio di risposta che restituisce il valore della stringa di query. Il terminale in cui è stato avviato il progetto mostra anche l'output del log quando si effettuano le richieste.Al termine, premere CTRL+C e digitare
y
per arrestare l'host delle funzioni.
Suggerimento
Durante l'avvio, l'host scarica e installa l'estensione di binding di archiviazione e altre estensioni di binding Microsoft. Questa installazione si verifica perché le estensioni di binding vengono abilitate per impostazione predefinita nel file host.json con le proprietà seguenti:
{
"version": "2.0",
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[1.*, 2.0.0)"
}
}
Se si verificano errori relativi alle estensioni di binding, controllare che le proprietà sopra indicate siano presenti in host.json.
Visualizzare il messaggio nella coda di Archiviazione di Azure
È possibile visualizzare la coda nel portale di Azure o in Microsoft Azure Storage Explorer. È anche possibile visualizzare la coda nell'interfaccia della riga di comando di Azure, come descritto nei passaggi seguenti:
Aprire il file local.setting.json del progetto di funzione e copiare il valore della stringa di connessione. In un terminale o in una finestra di comando eseguire il comando seguente per creare una variabile di ambiente denominata
AZURE_STORAGE_CONNECTION_STRING
e incollare il stringa di connessione specifico al posto di<MY_CONNECTION_STRING>
. Questa variabile di ambiente implica che non è necessario fornire la stringa di connessione a ogni comando successivo usando l'argomento--connection-string
.export AZURE_STORAGE_CONNECTION_STRING="<MY_CONNECTION_STRING>"
(Facoltativo) Usare il comando
az storage queue list
per visualizzare le code di archiviazione dell'account. L'output di questo comando deve includere una coda denominataoutqueue
, creata quando la funzione ha scritto il primo messaggio in tale coda.az storage queue list --output tsv
Usare il
az storage message get
comando per leggere il messaggio da questa coda, che deve essere il valore specificato durante il test della funzione in precedenza. Il comando legge e rimuove il primo messaggio dalla coda.echo `echo $(az storage message get --queue-name outqueue -o tsv --query '[].{Message:content}') | base64 --decode`
Poiché il corpo del messaggio viene archiviato con codifica base64, il messaggio deve essere decodificato prima di essere visualizzato. Dopo l'esecuzione di
az storage message get
, il messaggio viene rimosso dalla coda. Se è presente un solo messaggio inoutqueue
, quando si esegue questo comando una seconda volta non viene recuperato alcun messaggio e si riceve invece un errore.
Ridistribuire il progetto in Azure
Dopo aver verificato in locale che la funzione ha scritto un messaggio nella coda di Archiviazione di Azure, è possibile ridistribuire il progetto per aggiornare l'endpoint in esecuzione in Azure.
Nella cartella LocalFunctionsProj usare il comando func azure functionapp publish
per ridistribuire il progetto, sostituendo <APP_NAME>
con il nome dell'app.
func azure functionapp publish <APP_NAME>
Nella cartella del progetto locale usare il comando Maven seguente per ripubblicare il progetto:
mvn azure-functions:deploy
Eseguire la verifica in Azure
Come nell'argomento di avvio rapido precedente, usare un browser o un CURL per testare la funzione ridistribuita.
Esaminare di nuovo la coda di archiviazione, come descritto nella sezione precedente, per verificare che contenga il nuovo messaggio scritto nella coda.
Pulire le risorse
Al termine, usare il comando seguente per eliminare il gruppo di risorse e tutte le risorse contenute per evitare in incorrere in ulteriori costi.
az group delete --name AzureFunctionsQuickstart-rg
Passaggi successivi
La funzione di trigger HTTP è stata aggiornata per scrivere dati in una coda di archiviazione. Ora è possibile ottenere altre informazioni sullo sviluppo di Funzioni dalla riga di comando usando Core Tools e l'interfaccia della riga di comando di Azure: