Anslut Azure Functions till Azure Storage med kommandoradsverktyg

I den här artikeln integrerar du en Azure Storage-kö med funktionen och lagringskontot som du skapade i föregående snabbstartsartikel. Du uppnår den här integreringen med hjälp av en utdatabindning som skriver data från en HTTP-begäran till ett meddelande i kön. Att slutföra den här artikeln medför inga ytterligare kostnader utöver de få USD-centen i föregående snabbstart. Mer information om bindningar finns i Azure Functions-utlösare och bindningar.

Konfigurera din lokala miljö

Innan du börjar måste du slutföra artikeln Snabbstart: Skapa ett Azure Functions-projekt från kommandoraden. Om du redan har rensat resurser i slutet av den artikeln går du igenom stegen igen för att återskapa funktionsappen och relaterade resurser i Azure.

Innan du börjar måste du slutföra artikeln Snabbstart: Skapa ett Azure Functions-projekt från kommandoraden. Om du redan har rensat resurser i slutet av den artikeln går du igenom stegen igen för att återskapa funktionsappen och relaterade resurser i Azure.

Innan du börjar måste du slutföra artikeln Snabbstart: Skapa ett Azure Functions-projekt från kommandoraden. Om du redan har rensat resurser i slutet av den artikeln går du igenom stegen igen för att återskapa funktionsappen och relaterade resurser i Azure.

Innan du börjar måste du slutföra artikeln Snabbstart: Skapa ett Azure Functions-projekt från kommandoraden. Om du redan har rensat resurser i slutet av den artikeln går du igenom stegen igen för att återskapa funktionsappen och relaterade resurser i Azure.

Innan du börjar måste du slutföra artikeln Snabbstart: Skapa ett Azure Functions-projekt från kommandoraden. Om du redan har rensat resurser i slutet av den artikeln går du igenom stegen igen för att återskapa funktionsappen och relaterade resurser i Azure.

Innan du börjar måste du slutföra artikeln Snabbstart: Skapa ett Azure Functions-projekt från kommandoraden. Om du redan har rensat resurser i slutet av den artikeln går du igenom stegen igen för att återskapa funktionsappen och relaterade resurser i Azure.

Hämta Azure Storage-anslutningssträng

Tidigare skapade du ett Azure Storage-konto för funktionsappens användning. Anslutningssträng för det här kontot lagras på ett säkert sätt i appinställningarna i Azure. Genom att ladda ned inställningen till local.settings.json-filen kan du använda anslutningen för att skriva till en lagringskö i samma konto när du kör funktionen lokalt.

  1. Kör följande kommando från projektets rot och ersätt <APP_NAME> med namnet på funktionsappen från föregående steg. Det här kommandot skriver över alla befintliga värden i filen.

    func azure functionapp fetch-app-settings <APP_NAME>
    
  2. Öppna local.settings.json fil och leta upp värdet med namnet AzureWebJobsStorage, vilket är lagringskontot anslutningssträng. Du använder namnet AzureWebJobsStorage och anslutningssträng i andra avsnitt i den här artikeln.

Viktigt!

Eftersom den local.settings.json filen innehåller hemligheter som laddats ned från Azure utesluter du alltid den här filen från källkontrollen. Den .gitignore-fil som skapats med ett lokalt funktionsprojekt exkluderar filen som standard.

Registrera bindningstillägg

Förutom HTTP- och timerutlösare implementeras bindningar som tilläggspaket. Kör följande dotnet add package-kommando i terminalfönstret för att lägga till lagringstilläggspaketet i projektet.

dotnet add package Microsoft.Azure.Functions.Worker.Extensions.Storage.Queues --prerelease

Nu kan du lägga till bindningen för lagringsutdata i projektet.

Lägga till en utdatabindningsdefinition i funktionen

Även om en funktion bara kan ha en utlösare kan den ha flera indata- och utdatabindningar, vilket gör att du kan ansluta till andra Azure-tjänster och resurser utan att skriva anpassad integreringskod.

När du använder programmeringsmodellen Node.js v4 definieras bindningsattribut direkt i filen ./src/functions/HttpExample.js . Från föregående snabbstart innehåller filen redan en HTTP-bindning som definierats av app.http metoden.

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' };
    }
  },
});

När du använder programmeringsmodellen Node.js v4 definieras bindningsattribut direkt i filen ./src/functions/HttpExample.js . Från föregående snabbstart innehåller filen redan en HTTP-bindning som definierats av app.http metoden.

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,
});

Du deklarerar dessa bindningar i function.json-filen i funktionsmappen. Från föregående snabbstart innehåller din function.json-fil i mappen HttpExample två bindningar i bindings samlingen:

När du använder programmeringsmodellen Python v2 definieras bindningsattribut direkt i den function_app.py filen som dekoratörer. Från föregående snabbstart innehåller din function_app.py-fil redan en dekoratörsbaserad bindning:

import azure.functions as func
import logging

app = func.FunctionApp()

@app.function_name(name="HttpTrigger1")
@app.route(route="hello", auth_level=func.AuthLevel.ANONYMOUS)

Dekoratören route lägger till HttpTrigger- och HttpOutput-bindning till funktionen, vilket gör att funktionen kan utlösas när http-begäranden når den angivna vägen.

Om du vill skriva till en Azure Storage-kö från den här funktionen lägger du till dekoratören i queue_output funktionskoden:

@app.queue_output(arg_name="msg", queue_name="outqueue", connection="AzureWebJobsStorage")

I dekoratören arg_name identifierar du bindningsparametern som refereras till i koden, queue_name är namnet på kön som bindningen skriver till och connection är namnet på en programinställning som innehåller anslutningssträng för Lagringskontot. I snabbstarter använder du samma lagringskonto som funktionsappen AzureWebJobsStorage , som finns i inställningen (från local.settings.json fil). När inte queue_name finns skapar bindningen den vid första användningen.

"bindings": [
  {
    "authLevel": "function",
    "type": "httpTrigger",
    "direction": "in",
    "name": "Request",
    "methods": [
      "get",
      "post"
    ]
  },
  {
    "type": "http",
    "direction": "out",
    "name": "Response"
  }
]

Så här skriver du till en Azure Storage-kö:

  • Lägga till en extraOutputs egenskap i bindningskonfigurationen

    {
        methods: ['GET', 'POST'],
        extraOutputs: [sendToQueue], // add output binding to HTTP trigger
        authLevel: 'anonymous',
        handler: () => {}
    }
    
  • Lägg till en output.storageQueue funktion ovanför anropet app.http

    const sendToQueue: StorageQueueOutput = output.storageQueue({
      queueName: 'outqueue',
      connection: 'AzureWebJobsStorage',
    });
    

Den andra bindningen i samlingen heter res. Den här http bindningen är en utdatabindning (out) som används för att skriva HTTP-svaret.

Om du vill skriva till en Azure Storage-kö från den här funktionen lägger du till en out bindning av typen queue med namnet msg, enligt koden nedan:

    {
      "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"
    }
  ]
}

För en queue typ måste du ange namnet på kön i queueName och ange namnet på Azure Storage-anslutningen (från local.settings.json-filen ) i connection.

I ett C#-projekt definieras bindningarna som bindningsattribut för funktionsmetoden. Specifika definitioner beror på om din app körs i processen (C#-klassbiblioteket) eller i en isolerad arbetsprocess.

Öppna HttpExample.cs-projektfilen och lägg till följande MultiResponse klass:

public class MultiResponse
{
    [QueueOutput("outqueue",Connection = "AzureWebJobsStorage")]
    public string[] Messages { get; set; }
    public HttpResponseData HttpResponse { get; set; }
}

Med MultiResponse klassen kan du skriva till en lagringskö med namnet outqueue och ett HTTP-meddelande. Flera meddelanden kan skickas till kön eftersom QueueOutput attributet tillämpas på en strängmatris.

Egenskapen Connection anger anslutningssträng för lagringskontot. I det här fallet kan du utelämna Connection eftersom du redan använder standardlagringskontot.

I ett Java-projekt definieras bindningarna som bindningsanteckningar för funktionsmetoden. Filen function.json genereras sedan automatiskt baserat på dessa anteckningar.

Bläddra till platsen för funktionskoden under src/main/java, öppna projektfilen Function.java och lägg till följande parameter i metoddefinitionen run :

@QueueOutput(name = "msg", queueName = "outqueue", connection = "AzureWebJobsStorage") OutputBinding<String> msg

Parametern msg är en OutputBinding<T> typ som representerar en samling strängar. Dessa strängar skrivs som meddelanden till en utdatabindning när funktionen är klar. I det här fallet är utdata en lagringskö med namnet outqueue. Anslutningssträng för lagringskontot anges med connection metoden . Du skickar programinställningen som innehåller lagringskontot anslutningssträng i stället för att skicka själva anslutningssträng.

Metoddefinitionen run måste nu se ut som i följande exempel:

@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) {
    ...
}

Mer information om bindningar finns i Azure Functions-utlösare och bindningar ochkonfiguration av köutdata.

Lägg till kod för att använda utdatabindningen

Med köbindningen definierad kan du nu uppdatera funktionen för att ta emot msg utdataparametern och skriva meddelanden till kön.

Uppdatera HttpExample\function_app.py för att matcha följande kod, lägg till parametern msg i funktionsdefinitionen och msg.set(name) under -instruktionen 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
        )

Parametern msg är en instans av azure.functions.Out class. Metoden set skriver ett strängmeddelande till kön. I det här fallet skickas den name till funktionen i URL-frågesträngen.

Lägg till kod som använder utdatabindningsobjektet på context.extraOutputs för att skapa ett kömeddelande. Lägg till den här koden före retur-instruktionen.

context.extraOutputs.set(sendToQueue, [msg]);

I det här läget kan funktionen se ut så här:

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' };
    }
  },
});

Lägg till kod som använder utdatabindningsobjektet på context.extraOutputs för att skapa ett kömeddelande. Lägg till den här koden före retur-instruktionen.

context.extraOutputs.set(sendToQueue, [msg]);

I det här läget kan funktionen se ut så här:

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,
});

Lägg till kod som använder cmdleten Push-OutputBinding för att skriva text till kön med hjälp av utdatabindningen msg . Lägg till den här koden innan du anger OK-status i -instruktionen if .

$outputMsg = $name
Push-OutputBinding -name msg -Value $outputMsg

I det här läget måste funktionen se ut så här:

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
})

Ersätt den befintliga HttpExample klassen med följande kod:

    [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
        };
    }
}

Nu kan du använda den nya msg parametern för att skriva till utdatabindningen från funktionskoden. Lägg till följande kodrad före det lyckade svaret för att lägga till värdet name för i utdatabindningen msg .

msg.setValue(name);

När du använder en utdatabindning behöver du inte använda Azure Storage SDK-koden för autentisering, hämta en köreferens eller skriva data. Functions runtime- och köutdatabindning utför dessa uppgifter åt dig.

Metoden run måste nu se ut som i följande exempel:

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();
    }
}

Uppdatera testerna

Eftersom arketypen också skapar en uppsättning tester måste du uppdatera dessa tester för att hantera den nya msg parametern i metodsignaturen run .

Bläddra till platsen för testkoden under src/test/java, öppna Function.java projektfilen och ersätt kodraden under //Invoke med följande kod:

@SuppressWarnings("unchecked")
final OutputBinding<String> msg = (OutputBinding<String>)mock(OutputBinding.class);
final HttpResponseMessage ret = new Function().run(req, msg, context);

Observera att du inte behöver skriva någon kod för autentisering, hämta en köreferens eller skriva data. Alla dessa integreringsuppgifter hanteras enkelt i Azure Functions-körnings- och köutdatabindningen.

Kör funktionen lokalt

  1. Kör funktionen genom att starta den lokala Azure Functions-körningsvärden från mappen LocalFunctionProj .

    func start
    

    Mot slutet av utdata måste följande rader visas:

    Skärmbild av terminalfönstrets utdata när funktionen körs lokalt.

    Kommentar

    Om HttpExample inte visas som ovan startade du förmodligen värden utanför rotmappen i projektet. I så fall använder du Ctrl+C för att stoppa värden, går till projektets rotmapp och kör föregående kommando igen.

  2. Kopiera URL:en för HTTP-funktionen från den här utdatan till en webbläsare och lägg till frågesträngen ?name=<YOUR_NAME>, vilket gör den fullständiga URL:en till exempel http://localhost:7071/api/HttpExample?name=Functions. Webbläsaren bör visa ett svarsmeddelande som upprepar frågesträngsvärdet. Terminalen där du startade projektet visar även loggutdata när du gör begäranden.

  3. När du är klar trycker du på Ctrl + C och skriver y för att stoppa funktionsvärden.

Dricks

Under starten laddar värden ned och installerar lagringsbindningstillägget och andra Microsoft-bindningstillägg. Den här installationen sker eftersom bindningstillägg är aktiverade som standard i filen host.json med följande egenskaper:

{
    "version": "2.0",
    "extensionBundle": {
        "id": "Microsoft.Azure.Functions.ExtensionBundle",
        "version": "[1.*, 2.0.0)"
    }
}

Om du stöter på fel som rör bindningstillägg kontrollerar du att egenskaperna ovan finns i host.json.

Visa meddelandet i Azure Storage-kön

Du kan visa kön i Azure-portalen eller i Microsoft Azure Storage Explorer. Du kan också visa kön i Azure CLI enligt beskrivningen i följande steg:

  1. Öppna funktionsprojektets local.setting.json-fil och kopiera värdet för anslutningssträng. I ett terminal- eller kommandofönster kör du följande kommando för att skapa en miljövariabel med namnet AZURE_STORAGE_CONNECTION_STRINGoch klistra in din specifika anslutningssträng i stället för <MY_CONNECTION_STRING>. (Den här miljövariabeln innebär att du inte behöver ange anslutningssträng till varje efterföljande kommando med argumentet--connection-string.)

    export AZURE_STORAGE_CONNECTION_STRING="<MY_CONNECTION_STRING>"
    
  2. (Valfritt) az storage queue list Använd kommandot för att visa lagringsköerna i ditt konto. Utdata från det här kommandot måste innehålla en kö med namnet outqueue, som skapades när funktionen skrev sitt första meddelande till kön.

    az storage queue list --output tsv
    
  3. az storage message get Använd kommandot för att läsa meddelandet från den här kön, vilket bör vara det värde som du angav när du testade funktionen tidigare. Kommandot läser och tar bort det första meddelandet från kön.

    echo `echo $(az storage message get --queue-name outqueue -o tsv --query '[].{Message:content}') | base64 --decode`
    

    Eftersom meddelandetexten lagras base64-kodad måste meddelandet avkodas innan det visas. När du har kört az storage message gettas meddelandet bort från kön. Om det bara fanns ett meddelande i outqueuehämtar du inte ett meddelande när du kör det här kommandot en andra gång och får i stället ett fel.

Distribuera om projektet till Azure

Nu när du har verifierat lokalt att funktionen skrev ett meddelande till Azure Storage-kön kan du distribuera om projektet för att uppdatera slutpunkten som körs i Azure.

I mappen LocalFunctionsProj använder du func azure functionapp publish kommandot för att distribuera om projektet och ersätter<APP_NAME> med namnet på din app.

func azure functionapp publish <APP_NAME>

I den lokala projektmappen använder du följande Maven-kommando för att publicera om projektet:

mvn azure-functions:deploy

Verifiera i Azure

  1. Precis som i föregående snabbstart använder du en webbläsare eller CURL för att testa den omdistribuerade funktionen.

    Kopiera den fullständiga Anropa URL:en som visas i utdata från publiceringskommandot till ett webbläsaradressfält och lägga till frågeparametern &name=Functions. Webbläsaren bör visa samma utdata som när du körde funktionen lokalt.

  2. Granska lagringskö igen, enligt beskrivningen i föregående avsnitt, för att kontrollera att den innehåller det nya meddelandet som skrivits till kön.

Rensa resurser

När du är klar använder du följande kommando för att ta bort resursgruppen och alla dess inneslutna resurser för att undvika ytterligare kostnader.

az group delete --name AzureFunctionsQuickstart-rg

Nästa steg

Du har uppdaterat din HTTP-utlösta funktion för att skriva data till en lagringskö. Nu kan du lära dig mer om att utveckla Functions från kommandoraden med Core Tools och Azure CLI: