Conectar o Azure Functions ao Armazenamento do Azure usando o Visual Studio Code

O Azure Functions lhe permite conectar os serviços do Azure e outros recursos às funções sem precisar escrever seu próprio código de integração. Essas associações, que representam a entrada e a saída, são declaradas na definição de função. Dados de associações são fornecidos à função como parâmetros. Um gatilho é um tipo especial de associação de entrada. Embora uma função tenha apenas um gatilho, ela pode ter várias associações de entrada e de saída. Para saber mais, confira Conceitos de gatilhos e de associações do Azure Functions.

Neste artigo, você aprenderá a usar o Visual Studio Code para conectar o Armazenamento do Azure à função criada no artigo de início rápido anterior. A associação de saída que você adiciona a essa função escreve dados da solicitação HTTP em uma mensagem na fila.

A maioria das associações requer uma cadeia de conexão armazenada que o Functions usa para acessar o serviço vinculado. Para facilitar, use a conta de armazenamento que você criou com o aplicativo de funções. A conexão com essa conta já está armazenada em uma configuração de aplicativo chamada AzureWebJobsStorage.

Observação

No momento, este artigo só dá suporte ao Node.js v4 para Functions.

Configurar o ambiente local

Antes de começar, você precisa atender aos seguintes requisitos:

Este artigo pressupõe que você já esteja conectado à sua assinatura do Azure do Visual Studio Code. Você pode entrar executando Azure: Sign In na paleta de comandos.

Baixar as configurações do aplicativo de funções

No artigo de início rápido anterior, você criou um aplicativo de funções no Azure, acompanhado da conta de armazenamento necessária. A cadeia de conexão dessa conta é armazenada com segurança nas configurações de aplicativo no Azure. Neste artigo, você escreverá mensagens em uma Fila de armazenamento na mesma conta. Para se conectar à conta de armazenamento ao executar a função localmente, é necessário baixar as configurações do aplicativo para o arquivo local.settings.json.

  1. Pressione a tecla F1 para abrir a paleta de comandos, depois pesquise e execute o comando Azure Functions: Download Remote Settings....

  2. Escolha o aplicativo de função que você criou no artigo anterior. Selecione Sim para todos para substituir as configurações locais existentes.

    Importante

    Como o arquivo local.settings.json contém segredos, ele nunca é publicado e é excluído do controle do código-fonte.

  3. Copie o valor AzureWebJobsStorage, que é a chave do valor da cadeia de conexão da conta de armazenamento. Use esta conexão para verificar se a associação de saída funciona conforme o esperado.

Registrar as extensões de associação

Como você está usando uma associação de saída do Armazenamento de Filas, você precisa ter a extensão de associações de Armazenamento instalada antes de executar o projeto.

Seu projeto foi configurado para usar pacotes de extensão, que instalam automaticamente um conjunto predefinido de pacotes de extensão.

Os pacotes de extensão já estão habilitados no arquivo host.json na raiz no projeto, cuja aparência é semelhante ao seguinte exemplo:

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

Agora, você pode adicionar a associação de saída do armazenamento ao seu projeto.

Seu projeto foi configurado para usar pacotes de extensão, que instalam automaticamente um conjunto predefinido de pacotes de extensão.

Os pacotes de extensão já estão habilitados no arquivo host.json na raiz no projeto, cuja aparência é semelhante ao seguinte exemplo:

{
  "version": "2.0",
  "logging": {
    "applicationInsights": {
      "samplingSettings": {
        "isEnabled": true,
        "excludedTypes": "Request"
      }
    }
  },
  "extensionBundle": {
    "id": "Microsoft.Azure.Functions.ExtensionBundle",
    "version": "[4.*, 5.0.0)"
  }
}

Agora, você pode adicionar a associação de saída do armazenamento ao seu projeto.

Com exceção dos gatilhos de timer e HTTP, as associações são implementadas como pacotes de extensão. Execute o comando dotnet add package a seguir na janela Terminal para adicionar o pacote de extensão Armazenamento ao seu projeto.

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

Agora, você pode adicionar a associação de saída do armazenamento ao seu projeto.

Adicionar uma associação de saída

Para gravar em uma fila do Armazenamento do Microsoft Azure:

  • Adicionar uma propriedade extraOutputs à configuração de associação

    {
        methods: ['GET', 'POST'],
        extraOutputs: [sendToQueue], // add output binding to HTTP trigger
        authLevel: 'anonymous',
        handler: () => {}
    }
    
  • Adicionar uma função output.storageQueue acima da chamada app.http

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

Para gravar em uma fila do Armazenamento do Microsoft Azure:

  • Adicionar uma propriedade extraOutputs à configuração de associação

    {
        methods: ['GET', 'POST'],
        extraOutputs: [sendToQueue], // add output binding to HTTP trigger
        authLevel: 'anonymous',
        handler: () => {}
    }
    
  • Adicionar uma função output.storageQueue acima da chamada app.http

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

Nas Funções, cada tipo de associação exige um direction, type e um name exclusivo. A maneira como você define esses atributos depende do idioma do seu aplicativo de funções.

Os atributos de associação são definidos no arquivo function.json para uma determinada função. Dependendo do tipo de associação, outras propriedades podem ser necessárias. A configuração de saída da fila descreve os campos obrigatórios para uma associação de fila do Armazenamento do Azure. A extensão facilita a inclusão de associações no arquivo function.json.

Para criar uma associação, clique com o botão direito do mouse (Ctrl+clique no macOS) no arquivo function.json na pasta HttpTrigger e escolha Adicionar associação... . Siga os prompts para definir as seguintes propriedades de associação para a nova associação:

Prompt Valor Descrição
Selecionar direção de associação out A associação é uma associação de saída.
Selecionar associação com direção... Azure Queue Storage A associação é uma associação de fila do Armazenamento do Azure.
O nome usado para identificar essa associação em seu código msg Nome que identifica o parâmetro de associação referenciado em seu código.
A fila à qual a mensagem será enviada outqueue O nome da fila na qual a associação escreve. Quando o queueName não existe, a associação o cria no primeiro uso.
Selecione a configuração de "local.setting.json" AzureWebJobsStorage O nome de uma configuração de aplicativo que contém a cadeia de conexão da Conta de armazenamento. A configuração AzureWebJobsStorage contém a cadeia de conexão para a Conta de armazenamento criada com o aplicativo de funções.

Uma associação foi adicionada à matriz bindings no seu function.json, que deve ter a seguinte aparência:

      "name": "msg",
      "queueName": "outqueue",
      "connection": "AzureWebJobsStorage"
    }
  ]
}

Os atributos de associação são definidos decorando o código de função específico no arquivo function_app.py . Você usa o decorador queue_output para adicionar uma associação de dados de saída do armazenamento da Fila do Azure.

Usando o decorador queue_output, a direção da associação é implicitamente 'out' e o tipo é Fila de Armazenamento do Microsoft Azure. Adicione o seguinte decorador ao seu código de função em HttpExample\function_app.py:

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

Neste código, arg_name identifica o parâmetro de associação referenciado no seu código, queue_name é o nome da fila na qual a associação é gravada e connection é o nome de uma configuração de aplicativo que contém a cadeia de conexão da Conta de Armazenamento. No início rápido, você usa a mesma conta de armazenamento que o aplicativo de função, que está na configuração AzureWebJobsStorage. Quando o queue_name não existe, a associação o cria no primeiro uso.

Em um projeto C#, as associações são definidas como atributos de associação no método de função. Definições específicas dependem de o aplicativo ser executado em processo (biblioteca de classes C#) ou em um processo de trabalho isolado.

Abra o arquivo de projeto HttpExample.cs e adicione a seguinte classe MultiResponse:

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

A classe MultiResponse permite que você faça gravações em uma fila de armazenamento chamada outqueue e grave uma mensagem de êxito HTTP. Várias mensagens podem ser enviadas para a fila, porque o atributo QueueOutput é aplicado a uma matriz de cadeia de caracteres.

A propriedade Connection define a cadeia de conexão da conta de armazenamento. Nesse caso, você poderia omitir Connection porque já está usando a conta de armazenamento padrão.

Em um projeto Java, as associações são definidas como anotações de associação no método de função. O arquivo function.json é então gerado automaticamente com base nessas anotações.

Procure a localização do código de função em src/main/java, abra o arquivo de projeto Function.java e adicione o seguinte parâmetro à definição do método run:

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

O parâmetro msg é um tipo OutputBinding<T>, que representa uma coleção de cadeias de caracteres que são gravadas como mensagens em uma associação de saída quando a função é concluída. Nesse caso, a saída é uma fila de armazenamento denominada outqueue. A cadeia de conexão para a conta de armazenamento é definida pelo método connection. Em vez da própria cadeia de conexão, passe a configuração de aplicativo que contém a cadeia de conexão da conta de armazenamento.

A definição do método run agora deverá ser semelhante ao seguinte exemplo:

@FunctionName("HttpExample")
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) {

Adicionar o código que usa a associação de saída

Depois que a associação é definida, você pode usar o name da associação para acessá-la como um atributo na assinatura de função. Ao usar uma associação de saída, não é necessário usar o código do SDK do Armazenamento do Azure para se autenticar, para obter uma referência de fila ou para escrever dados. O runtime do Functions e a associação de saída da fila fazem essas tarefas para você.

Adicione um código que usa o objeto de associação de saída em context.extraOutputs para criar uma mensagem da fila. Adicione este código antes da instrução return.

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

Nesse momento, sua função deve ser a seguinte:

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

Adicione um código que usa o objeto de associação de saída em context.extraOutputs para criar uma mensagem da fila. Adicione este código antes da instrução return.

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

Nesse momento, sua função deve ser a seguinte:

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

Adicione código que usa o cmdlet Push-OutputBinding para gravar texto na fila usando a associação de saída msg. Adicione esse código antes de definir o status como OK na instrução if.

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

Neste ponto, sua função deve ser a seguinte:

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

Atualize HttpExample\__init__.py para que corresponda ao seguinte código, adicionando o parâmetro msg à definição de função e msg.set(name) abaixo da instrução 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
        )

O parâmetro msg é uma instância do azure.functions.Out class. O método set grava uma mensagem de cadeia de caracteres na fila. Nesse caso, é o name passado para a função na cadeia de caracteres de consulta de URL.

Substitua a classe HttpExample existente pelo seguinte código:

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

Agora, você pode usar o novo parâmetro msg para fazer a gravação na associação de saída por meio do código de função. Adicione a linha de código a seguir antes da resposta de êxito para adicionar o valor de name à associação de saída msg.

msg.setValue(name);

Ao usar uma associação de saída, não é necessário usar o código do SDK do Armazenamento do Azure para se autenticar, para obter uma referência de fila ou para escrever dados. O runtime do Functions e a associação de saída da fila fazem essas tarefas para você.

O método run agora deverá ser semelhante ao seguinte exemplo:

@FunctionName("HttpExample")
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();
    }
}

Atualizar os testes

Como o arquétipo também cria um conjunto de testes, você precisa atualizar esses testes para manipular o novo parâmetro msg na assinatura do método run.

Procure a localização do código de teste em src/test/java, abra o arquivo de projeto Function.java e substitua a linha de código em //Invoke pelo código a seguir.

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

Executar a função localmente

O Visual Studio Code integra-se ao Azure Functions Core Tools para permitir que você execute esse projeto em seu computador de desenvolvimento local antes da publicação no Azure. Se você ainda não tiver o Core Tools instalado localmente, será solicitado que você o instale na primeira vez que executar o projeto.

  1. Para chamar sua função, pressione F5 para iniciar o projeto de aplicativo de funções. O painel Terminal exibirá a saída do Core Tools. Seu aplicativo é iniciado no painel Terminal. Você pode ver o ponto de extremidade de URL de sua função disparada por HTTP localmente.

    Captura de tela da saída do Visual Studio Code da função local.

    Se o Core Tools ainda não estiver instalado, selecione Instalar para instalar o Core Tools quando solicitado a fazê-lo.
    Se você tiver problemas com a execução no Windows, verifique se o terminal padrão do Visual Studio Code não está definido como bash WSL.

  2. Com o Core Tools em execução, acesse a área Azure: Funções. Em Funções, expanda Projeto Local>Funções. Clique com o botão direito do mouse (Windows) ou clique em CTRL - (macOS) na função HttpExample e escolha Função Executar Agora... .

    Captura de executar função agora no Visual Studio Code.

  3. Em Insira o corpo da solicitação, pressione ENTER para enviar uma mensagem à função.

  4. Quando a função é executada localmente e retorna uma resposta, uma notificação é gerada no Visual Studio Code. As informações sobre a execução da função são mostradas no painel Terminal.

  5. Pressione Ctrl + C para parar o Core Tools e desconectar o depurador.

Executar a função localmente

  1. Como no artigo anterior, clique em F5 para iniciar o projeto do aplicativo de funções e o Core Tools.

  2. Com o Core Tools em execução, acesse a área Azure: Funções. Em Funções, expanda Projeto Local>Funções. Clique com o botão direito do mouse (CTRL - clique no Mac) na função HttpExample e selecione Executar Função Agora….

    Captura de tela de como executar a função no Visual Studio Code.

  3. Em Insira o corpo da solicitação, você verá o valor do corpo da mensagem de solicitação { "name": "Azure" }. Pressione Enter para enviar essa mensagem de solicitação à função.

  4. Depois que uma resposta for retornada, clique em CTRL + C para interromper o Core Tools.

Como você está usando a cadeia de conexão de armazenamento, a função se conecta à conta de armazenamento do Azure durante a execução local. Uma nova fila denominada outqueue é criada na sua conta de armazenamento pelo tempo de execução do Functions quando a associação de saída é usada pela primeira vez. Você usará o Gerenciador de Armazenamento para verificar se a fila foi criada junto com a nova mensagem.

Conectar o Gerenciador de Armazenamento à sua conta

Ignore esta seção se você já instalou o Gerenciador de Armazenamento do Azure e o conectou à sua conta do Azure.

  1. Execute a ferramenta Gerenciador de Armazenamento do Azure, clique no ícone de conexão à esquerda e selecione Adicionar uma conta.

    Captura de tela de como adicionar uma conta do Azure ao Gerenciador de Armazenamento do Microsoft Azure.

  2. Na caixa de diálogo Conectar, escolha Adicionar uma conta do Azure, escolha seu Ambiente do Azure e selecione Entrar….

    Captura de tela da entrada na janela da conta do Azure.

Depois de entrar na sua conta, você verá todas as assinaturas do Azure associadas à ela. Escolha sua assinatura e selecione Abrir Gerenciador.

Examinar a fila de saída

  1. No Visual Studio Code, pressione F1 para abrir a paleta de comandos, procure e execute o comando Azure Storage: Open in Storage Explorer e escolha o nome da sua conta de armazenamento. Sua conta de armazenamento é aberta no Gerenciador de Armazenamento do Azure.

  2. Expanda o nó Filas e selecione a fila denominada outqueue.

    A fila contém a mensagem que a associação de saída de fila criou quando você executou a função disparada por HTTP. Se você tiver invocado a função com o valor name padrão do Azure, a mensagem da fila será Nome transmitido à função: Azure.

    Captura de tela da mensagem da fila mostrada no Gerenciador de Armazenamento do Azure.

  3. Execute a função novamente, envie outra solicitação e você verá uma nova mensagem na fila.

Agora, chegou a hora de republicar o aplicativo de funções atualizado no Azure.

Reimplementar e verificar o aplicativo atualizado

  1. No Visual Studio Code, pressione F1 para abrir a paleta de comandos. Na paleta de comandos, pesquise e selecione Azure Functions: Deploy to function app....

  2. Escolha o aplicativo de funções que você criou no primeiro artigo. Como você está reimplantando seu projeto no mesmo aplicativo, selecione Implantar para descartar o aviso de substituição de arquivos.

  3. Após a conclusão da implantação, use novamente o recurso Executar Função Agora… para disparar a função no Azure.

  4. Novamente, veja a mensagem na fila de armazenamento para verificar se a associação de saída gera uma nova mensagem na fila.

Limpar os recursos

No Azure, os Recursos se referem a aplicativos de funções, funções, contas de armazenamento e assim por diante. Eles são agrupados em grupos de recursos e você pode excluir tudo junto ao excluir o grupo.

Você criou recursos para concluir esses guias de início rápido. Você pode ser cobrado por esses recursos, dependendo do status de conta e preços do serviço. Caso não precise mais dos recursos, é possível excluí-los desta maneira:

  1. No Visual Studio Code, pressione F1 para abrir a paleta de comandos. Na paleta de comandos, pesquise e selecione Azure: Open in portal.

  2. Escolha seu aplicativo de funções e pressione ENTER. A página do aplicativo de funções é aberta no portal do Azure.

  3. Na guia Visão geral, selecione o link nomeado ao lado de Grupo de recursos.

    Captura de tela de seleção do grupo de recursos para excluir da página do aplicativo de funções.

  4. Na página Grupo de recursos, revise a lista de recursos incluídos e verifique se eles são aqueles que você deseja excluir.

  5. Selecione Excluir grupo de recursos e siga as instruções.

    A exclusão poderá levar alguns minutos. Ao ser concluída, uma notificação será exibida por alguns segundos. Também é possível selecionar o ícone de sino na parte superior da página para exibir a notificação.

Próximas etapas

Você atualizou sua função disparada por HTTP para gravar dados em uma Fila de armazenamento. Agora você pode saber mais sobre o desenvolvimento no Functions usando o Visual Studio Code: