Compartilhar via


Desenvolva funções da biblioteca de classes C# usando o Azure Functions

Este artigo é uma introdução ao desenvolvimento do Azure Functions usando o script C# em biblioteca de classes .NET. Essas bibliotecas de classes são usadas para execução em processo com o runtime do Functions. As funções do .NET podem, como alternativa, executar _isolated no runtime do Functions, o que oferece várias vantagens. Para saber mais, confira o modelo de trabalho isolado. Para obter uma comparação abrangente entre esses dois modelos, confira Diferenças entre o modelo em processo e o modelo de trabalho isolado.

Importante

Este artigo serve para funções de biblioteca de classes do .NET, que são executadas em processo com o runtime. Suas funções C# também podem ficar fora do processo e isoladas do runtime do Functions. O modelo de processo de trabalho isolado é a única maneira de executar versões não LTS dos aplicativos .NET e .NET Framework nas versões atuais do runtime do Functions. Para saber mais, confira funções de processo de trabalho isolado no .NET. Para obter uma comparação abrangente entre o processo e processo de trabalho isolado no .NET Functions, confira Diferenças entre o processo e o processo de trabalho isolado no .NET Azure Functions.

Como desenvolvedor de C#, você também pode gostar de um dos seguintes artigos:

Introdução Conceitos Amostras/aprendizado guiado

O Azure Functions oferece suporte às linguagens de programação C# e script C#. Se estiver procurando diretrizes sobre como usar C# no portal do Azure, consulte Referência do desenvolvedor de script C# (.csx).

Versões com suporte

As versões runtime do Functions dão suporte a versões específicas do .NET. Saiba mais sobre as versões do Functions, confira Visão geral de versões do Azure Functions runtime. O suporte a uma versão depende de suas funções serem executadas em processo ou no processo de trabalho isolado.

Observação

Para saber como alterar a versão de runtime do Functions usada pelo aplicativo de funções, confira Exibir e atualizar a versão de runtime atual.

A tabela a seguir mostra o nível mais alto do .NET ou .NET Framework que pode ser usado com uma versão específica do Functions.

Versão do runtime do Functions Modelo de trabalho isolado Modelo em processo4
Funções 4.x1 .NET 9.0
.NET 8.0
.NET Framework 4.82
.NET 8.0
Functions 1.x3 N/D .NET Framework 4.8

1 Anteriormente, o .NET 6 tinha suporte nos dois modelos, mas chegou ao fim do suporte oficial em 12 de novembro de 2024. Anteriormente, o .NET 7 tinha suporte no modelo de trabalho isolado, mas chegou ao fim do suporte oficial em 14 de maio de 2024.

2 O processo de build também exige o SDK do .NET.

3 O suporte para a versão 1.x do runtime do Azure Functions termina em 14 de setembro de 2026. Para obter mais informações, confira este comunicado de suporte. Para obter suporte completo contínuo, você deve migrar seus aplicativos para a versão 4.x.

4 O suporte para o modelo em processo termina em 10 de novembro de 2026. Para obter mais informações, confira este comunicado de suporte. Para obter suporte completo contínuo, você deve migrar seus aplicativos para o modelo de trabalho isolado.

Para receber as notícias mais recentes sobre as versões de Azure Functions, incluindo a remoção de versões secundárias específicas mais antigas, acompanhe os comunicados de Serviço de Aplicativo do Azure.

Atualizando para o .NET 8 de destino

Os aplicativos que usam o modelo em processo podem ser direcionados ao .NET 8 seguindo as etapas descritas nesta seção. No entanto, se você optar por exercer essa opção, ainda deverá começar a planejar sua migração para o modelo de trabalho isolado antes do fim do suporte para o modelo em processo em 10 de novembro de 2026.

Muitos aplicativos podem alterar a configuração do aplicativo de funções no Azure sem atualizações para código ou reimplantação. Para executar o .NET 8 com o modelo em processo, são necessárias três configurações:

  • A configuração do aplicativo FUNCTIONS_WORKER_RUNTIME precisa ser definida com o valor “dotnet”.
  • A configuração FUNCTIONS_EXTENSION_VERSION do aplicativo precisa ser definida com o valor "~4".
  • A configuração FUNCTIONS_INPROC_NET8_ENABLED do aplicativo precisa ser definida com o valor "1".
  • Você precisa atualizar a configuração de pilha para fazer referência ao .NET 8.

O suporte para .NET 8 ainda usa a versão 4.x do runtime do Functions e nenhuma alteração na versão de runtime configurada é necessária.

Para atualizar seu projeto local, primeiro verifique se você está usando as versões mais recentes das ferramentas locais. Verifique então se o projeto faz referência à versão 4.4.0 ou posterior do Microsoft.NET.Sdk.Functions. Em seguida, você pode alterar seu TargetFramework para "net8.0". Você também precisa atualizar local.settings.json para incluir ambos FUNCTIONS_WORKER_RUNTIME definido como "dotnet" e FUNCTIONS_INPROC_NET8_ENABLED definido como "1".

Veja o seguinte exemplo de um arquivo mínimo project com estas alterações:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <AzureFunctionsVersion>v4</AzureFunctionsVersion>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.NET.Sdk.Functions" Version="4.4.0" />
  </ItemGroup>
  <ItemGroup>
    <None Update="host.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Update="local.settings.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <CopyToPublishDirectory>Never</CopyToPublishDirectory>
    </None>
  </ItemGroup>
</Project>

Veja o seguinte exemplo de um arquivo mínimo local.settings.json com estas alterações:

{
    "IsEncrypted": false,
    "Values": {
        "AzureWebJobsStorage": "UseDevelopmentStorage=true",
        "FUNCTIONS_INPROC_NET8_ENABLED": "1",
        "FUNCTIONS_WORKER_RUNTIME": "dotnet"
    }
}

Se o aplicativo usar Microsoft.Azure.DurableTask.Netherite.AzureFunctions, verifique se ele tem como destino a versão 1.5.3 ou posterior. Devido a uma alteração de comportamento no .NET 8, os aplicativos com versões mais antigas do pacote vão gerar uma exceção ambígua do construtor.

Talvez seja necessário fazer outras alterações no aplicativo de acordo com o suporte de versão das outras dependências dele.

A versão 4.x do runtime do Functions fornece funcionalidade equivalente para .NET 6 e .NET 8. O modelo em processo não inclui recursos ou atualizações adicionais que se integram aos novos recursos do .NET 8. Por exemplo, o runtime não dá suporte a serviços com chave. Para aproveitar ao máximo os recursos e aprimoramentos mais recentes do .NET 8, você deve migrar para o modelo de trabalho isolado.

Projeto de biblioteca de classes de funções

No Visual Studio, o modelo de projeto do Azure Functions cria um projeto de biblioteca de classes do C# que contém os seguintes arquivos:

Quando você compila o projeto, uma estrutura de pastas semelhante ao exemplo a seguir é gerada no diretório de saída da build:

<framework.version>
 | - bin
 | - MyFirstFunction
 | | - function.json
 | - MySecondFunction
 | | - function.json
 | - host.json

Esse é o diretório implantado no aplicativo de funções no Azure. As extensões de associação necessárias na versão 2.x do runtime das Funções são adicionadas ao projeto como pacotes do NuGet.

Importante

O processo de compilação cria um arquivo function.json para cada função. Esse arquivo function.json não deve ser editado diretamente. Você não pode alterar a configuração de associação ou desabilitar a função por meio da edição desse arquivo. Para aprender como desabilitar uma função, consulte Como desabilitar funções.

Métodos reconhecidos como funções

Em uma biblioteca de classes, uma função é um método com um FunctionName e um atributo de gatilho, conforme mostrado no seguinte exemplo:

public static class SimpleExample
{
    [FunctionName("QueueTrigger")]
    public static void Run(
        [QueueTrigger("myqueue-items")] string myQueueItem, 
        ILogger log)
    {
        log.LogInformation($"C# function processed: {myQueueItem}");
    }
} 

O atributo FunctionName marca o método como um ponto de entrada da função. O nome deve ser exclusivo dentro de um projeto, começar com uma letra e conter apenas letras, números, _ e -, até 127 caracteres. Modelos de projeto geralmente criam um método chamado Run, mas o nome do método pode ser qualquer nome de método C# válido. O exemplo acima mostra um método estático sendo usado, mas as funções não precisam ser estáticas.

O atributo de gatilho especifica o tipo de gatilho e associa dados de entrada a um parâmetro de método. A função de exemplo é disparada por uma mensagem de fila, a qual é transmitida para o método no parâmetro myQueueItem.

Parâmetros de assinatura do método

A assinatura do método pode conter parâmetros diferentes daquela usada com o atributo de gatilho. Aqui estão alguns outros parâmetros que você pode incluir:

Não importa a ordem dos parâmetros na assinatura de função. Por exemplo, você pode inserir os parâmetros de gatilho antes ou depois de outras associações e inserir o parâmetro do agente antes ou depois dos parâmetros de gatilho ou associação.

Associações de saída

Uma função pode ter nenhuma ou várias associações de saída definidas usando parâmetros de saída.

O exemplo a seguir modifica o anterior por adicionar uma associação de fila de saída chamada myQueueItemCopy. A função grava o conteúdo da mensagem que aciona a função para uma nova mensagem em uma fila diferente.

public static class SimpleExampleWithOutput
{
    [FunctionName("CopyQueueMessage")]
    public static void Run(
        [QueueTrigger("myqueue-items-source")] string myQueueItem, 
        [Queue("myqueue-items-destination")] out string myQueueItemCopy,
        ILogger log)
    {
        log.LogInformation($"CopyQueueMessage function processed: {myQueueItem}");
        myQueueItemCopy = myQueueItem;
    }
}

Os valores atribuídos a associações de saída são gravados quando a função sai. Você pode usar mais de uma associação de saída em uma função de forma simples, atribuindo valores a vários parâmetros de saída.

Os artigos de referência de associação (Filas de armazenamento, por exemplo) explicam quais tipos de parâmetro você pode usar com os atributos de associação de gatilho, entrada ou saída.

Exemplo de expressões de associação

O código a seguir obtém o nome da fila para monitorar a partir de uma configuração de aplicativo, e ele obtém a hora de criação da mensagem da fila no parâmetro insertionTime.

public static class BindingExpressionsExample
{
    [FunctionName("LogQueueMessage")]
    public static void Run(
        [QueueTrigger("%queueappsetting%")] string myQueueItem,
        DateTimeOffset insertionTime,
        ILogger log)
    {
        log.LogInformation($"Message content: {myQueueItem}");
        log.LogInformation($"Created at: {insertionTime}");
    }
}

function.json gerado automaticamente

O processo de compilação cria um arquivo function.json em uma pasta de função na pasta de compilação. Conforme observado anteriormente, esse arquivo não deve ser editado diretamente. Você não pode alterar a configuração de associação ou desabilitar a função por meio da edição desse arquivo.

O objetivo desse arquivo é fornecer informações para o controlador de escala usado para dimensionar decisões no plano de Consumo. Por esse motivo, o arquivo não tem informações de associações de entrada/saída, apenas de gatilho.

O arquivo function.json gerado inclui uma propriedade configurationSource que indica o runtime a ser usado em atributos .NET para associações, em vez da configuração do function.json. Veja um exemplo:

{
  "generatedBy": "Microsoft.NET.Sdk.Functions-1.0.0.0",
  "configurationSource": "attributes",
  "bindings": [
    {
      "type": "queueTrigger",
      "queueName": "%input-queue-name%",
      "name": "myQueueItem"
    }
  ],
  "disabled": false,
  "scriptFile": "..\\bin\\FunctionApp1.dll",
  "entryPoint": "FunctionApp1.QueueTrigger.Run"
}

Microsoft.NET.Sdk.Functions

A geração do arquivo function.json é realizada pelo pacote NuGet Microsoft NET.Sdk.Functions.

O exemplo a seguir mostra as partes relevantes dos .csproj arquivos que possuem estruturas de destino diferentes do mesmo Sdk pacote:

<PropertyGroup>
  <TargetFramework>net8.0</TargetFramework>
  <AzureFunctionsVersion>v4</AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
  <PackageReference Include="Microsoft.NET.Sdk.Functions" Version="4.5.0" />
</ItemGroup>

Importante

A partir da versão 4.0.6517 das Principais Ferramentas, projetos de modelo em processo devem referenciar a versão 4.5.0 ou posterior de Microsoft.NET.Sdk.Functions. Se uma versão anterior for usada, o comando func start apresentará um erro.

Entre as dependências do pacote Sdk estão os gatilhos e associações. Um projeto do 1.x se refere a gatilhos e associações do 1.x, pois os gatilhos e associações são direcionados ao .NET Framework, enquanto os gatilhos e associações do 4.x são direcionados ao .NET Core.

O pacote Sdk também depende do Sdk e, indiretamente, do WindowsAzure.Storage. Essas dependências garantem que seu projeto use as versões desses pacotes que funcionam com a versão de runtime do Functions para a qual o projeto é direcionado. Por exemplo, o Newtonsoft.Json tem a versão 11 para o .NET Framework 4.6.1, mas o runtime do Functions direcionado para o .NET Framework 4.6.1 só é compatível com o Newtonsoft.Json 9.0.1. Portanto, o código de sua função nesse projeto também tem que usar Newtonsoft.Json 9.0.1.

O código-fonte para Microsoft.NET.Sdk.Functionsestá disponível no repositório GitHub Microsoft.NET.Sdk.Functions.

Versão de tempo de execução local

O Visual Studio usa o Azure Functions Core Tools para executar projetos do Functions em seu computador local. As Ferramentas Essenciais são uma interface de linha de comando para o runtime do Functions.

Se você instalar as Ferramentas Principais usando o pacote do Windows Installer (MSI) ou usando npm, isso não afetará a versão das Ferramentas Principais usada pelo Visual Studio. Para a versão de runtime do Functions 1.x, o Visual Studio armazena as versões das Ferramentas Essenciais em %USERPROFILE%\AppData\Local\Azure.Functions.Cli e usa a versão mais recente armazenada ali. No Functions 4.x, as Ferramentas Essenciais serão incluídas na extensão Azure Functions e Ferramentas de Trabalhos Web. No Functions 1.x, você pode ver qual versão está sendo usada na saída do console ao executar um projeto do Functions:

[3/1/2018 9:59:53 AM] Starting Host (HostId=contoso2-1518597420, Version=2.0.11353.0, ProcessId=22020, Debug=False, Attempt=0, FunctionsExtensionVersion=)

ReadyToRun

Você pode compilar seu aplicativo de funções como binários ReadyToRun. ReadyToRun é uma forma de compilação antecipada que pode melhorar o desempenho de inicialização, para ajudar a reduzir o impacto da inicialização a frio durante a execução em um plano de Consumo.

O ReadyToRun está disponível no .NET 6 e versões posteriores e tem como requisito a versão 4.0 ou posterior do runtime do Azure Functions.

Para compilar seu projeto como ReadyToRun, atualize o arquivo de projeto adicionando os elementos <PublishReadyToRun> e <RuntimeIdentifier>. Veja a seguir a configuração para a publicação em um aplicativo de funções de 32 bits do Windows.

<PropertyGroup>
  <TargetFramework>net8.0</TargetFramework>
  <AzureFunctionsVersion>v4</AzureFunctionsVersion>
  <PublishReadyToRun>true</PublishReadyToRun>
  <RuntimeIdentifier>win-x86</RuntimeIdentifier>
</PropertyGroup>

Importante

Do .NET 6 em diante, o suporte para a compilação de ReadyToRun composta foi adicionado. Confira as restrições de arquitetura e plataforma cruzada do ReadyToRun.

Você também pode criar seu aplicativo com ReadyToRun na linha de comando. Para obter mais informações, consulte a opção -p:PublishReadyToRun=true em dotnet publish.

Tipos com suporte para associações

Cada associação tem seus próprios tipos com suporte. Por exemplo, um atributo de gatilho de blob pode ser aplicado a um parâmetro de cadeia de caracteres, um parâmetro POCO, um parâmetro CloudBlockBlob ou qualquer um dos vários outros tipos com suporte. O artigo de referência de associação para associações de blob lista todos os tipos de parâmetro com suporte. Para obter mais informações, consulte Gatilhos e associações e os documentos de referência de associação para cada tipo de associação.

Dica

Se você planeja usar as ligações HTTP ou WebHook, planeje evitar o esgotamento de porta que pode ser causado pela instanciação incorreta do HttpClient. Para saber mais, confira Como gerenciar conexões no Azure Functions.

Associando ao valor de retorno do método

Você pode usar um valor de retorno do método para uma associação de saída, aplicando o atributo ao valor de retorno do método. Para obter exemplos, consulte Gatilhos e associações.

Use o valor retornado apenas se uma execução de função com êxito sempre resultar em um valor retornado a ser passado para a associação de saída. Caso contrário, use ICollector ou IAsyncCollector, conforme mostrado na seção a seguir.

Gravando vários valores de saída

Para gravar vários valores em uma associação de saída ou se uma invocação de função com êxito não resultar em nada a ser passado para a associação de saída, use os tipos ICollector ou IAsyncCollector. Esses tipos são coleções somente gravação que são gravadas na associação de saída quando o método é concluído.

Este exemplo grava várias mensagens de fila na mesma fila usando ICollector:

public static class ICollectorExample
{
    [FunctionName("CopyQueueMessageICollector")]
    public static void Run(
        [QueueTrigger("myqueue-items-source-3")] string myQueueItem,
        [Queue("myqueue-items-destination")] ICollector<string> myDestinationQueue,
        ILogger log)
    {
        log.LogInformation($"C# function processed: {myQueueItem}");
        myDestinationQueue.Add($"Copy 1: {myQueueItem}");
        myDestinationQueue.Add($"Copy 2: {myQueueItem}");
    }
}

Async

Para tornar uma função assíncrona, use a palavra-chave async e retorne um objeto Task.

public static class AsyncExample
{
    [FunctionName("BlobCopy")]
    public static async Task RunAsync(
        [BlobTrigger("sample-images/{blobName}")] Stream blobInput,
        [Blob("sample-images-copies/{blobName}", FileAccess.Write)] Stream blobOutput,
        CancellationToken token,
        ILogger log)
    {
        log.LogInformation($"BlobCopy function processed.");
        await blobInput.CopyToAsync(blobOutput, 4096, token);
    }
}

Não é possível usar parâmetros out em funções assíncronas. Para associações de saída, use o valor de retorno de função ou um objeto coletor.

Tokens de cancelamento

Uma função pode aceitar um parâmetro CancellationToken que permite ao sistema operacional notificar seu código quando a função está prestes a ser encerrada. Você pode usar essa notificação para certificar-se de que a função não finalize inesperadamente de uma maneira que os dados fiquem em um estado inconsistente.

Considere o caso quando você tem uma função que processa mensagens em lotes. A função disparada pelo Barramento de Serviço do Azure a seguir processa uma matriz de objetos de ServiceBusReceivedMessage, que representa um lote de mensagens de entrada a serem processadas por uma invocação de função específica:

using Azure.Messaging.ServiceBus;
using System.Threading;

namespace ServiceBusCancellationToken
{
    public static class servicebus
    {
        [FunctionName("servicebus")]
        public static void Run([ServiceBusTrigger("csharpguitar", Connection = "SB_CONN")]
               ServiceBusReceivedMessage[] messages, CancellationToken cancellationToken, ILogger log)
        {
            try
            { 
                foreach (var message in messages)
                {
                    if (cancellationToken.IsCancellationRequested)
                    {
                        log.LogInformation("A cancellation token was received. Taking precautionary actions.");
                        //Take precautions like noting how far along you are with processing the batch
                        log.LogInformation("Precautionary activities --complete--.");
                        break;
                    }
                    else
                    {
                        //business logic as usual
                        log.LogInformation($"Message: {message} was processed.");
                    }
                }
            }
            catch (Exception ex)
            {
                log.LogInformation($"Something unexpected happened: {ex.Message}");
            }
        }
    }
}

Registrando em log

Você pode gravar saídas em logs no seu código de função que apareçam como rastreamentos no Application Insights. A maneira recomendada para gravar nos logs é incluir um parâmetro do tipo ILogger, que normalmente recebe o nome de log. A Versão 1.x do runtime do Functions usava o TraceWriter, que também grava no Application Insights, mas não dá suporte a logs estruturados. Não use o Console.Write para gravar seus logs, pois esses dados não são capturados pelo Application Insights.

ILogger

Em sua definição de função, inclua um parâmetro ILogger, que oferece suporte a logs estruturados.

Com um objeto ILogger, você chama os Log<level> métodos de extensão no ILogger para criar logs. O código a seguir grava logs de Information com a categoria Function.<YOUR_FUNCTION_NAME>.User.:

public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, ILogger logger)
{
    logger.LogInformation("Request for item with key={itemKey}.", id);

Para saber mais sobre como as funções implementam o ILogger, consulte ILogger. As categorias prefixadas com Function pressupõem que você esteja usando uma instância ILogger. Se você optar por usar um ILogger<T>, o nome da categoria poderá, em vez disso, ser baseado em T.

Registro em log estruturado

A ordem dos espaços reservados, não seus nomes, determina quais parâmetros são usados na mensagem de log. Suponha que você tenha o seguinte código:

string partitionKey = "partitionKey";
string rowKey = "rowKey";
logger.LogInformation("partitionKey={partitionKey}, rowKey={rowKey}", partitionKey, rowKey);

Se você mantiver a mesma cadeia de caracteres de mensagem e inverter a ordem dos parâmetros, o texto da mensagem resultante terá os valores nos locais errados.

Os espaços reservados são tratados dessa forma para que você possa fazer registro em log estruturado. O Application Insights armazena os pares nome-valor do parâmetro e a cadeia de caracteres de mensagem. O resultado é que os argumentos da mensagem tornam-se campos que você pode consultar.

Se sua chamada de método do agente for semelhante ao exemplo anterior, você pode consultar o campo customDimensions.prop__rowKey. O prefixo prop__ é adicionado para garantir que não haja colisões entre campos que o runtime adiciona e campos que o código de função adiciona.

Você também pode consultar a cadeia de caracteres da mensagem original referenciando o campo customDimensions.prop__{OriginalFormat}.

Aqui está uma representação JSON de exemplo de dados customDimensions:

{
  "customDimensions": {
    "prop__{OriginalFormat}":"C# Queue trigger function processed: {message}",
    "Category":"Function",
    "LogLevel":"Information",
    "prop__message":"c9519cbf-b1e6-4b9b-bf24-cb7d10b1bb89"
  }
}

Registrar telemetria personalizada

Há uma versão do SDK do Application Insights específica do Functions, que você pode usar para enviar dados de telemetria personalizada das suas funções para o Application Insights: Microsoft.Azure.WebJobs.Logging.ApplicationInsights. Use o comando a seguir, no prompt de comando, para instalar esse pacote:

dotnet add package Microsoft.Azure.WebJobs.Logging.ApplicationInsights --version <VERSION>

Neste comando, substitua <VERSION> por uma versão desse pacote que dê suporte à versão instalada do <VERSION>.

Os exemplos de C# a seguir usam a API de telemetria personalizada. O exemplo é para uma biblioteca de classes do .NET, mas o código do Application Insights é o mesmo para o script C#.

A versão de runtime 2.x e posteriores usam recursos mais recentes no Application Insights para correlacionar automaticamente a telemetria com a operação atual. Não é necessário definir manualmente os campos da operação Id, ParentId, ou Name.

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;

using Microsoft.ApplicationInsights;
using Microsoft.ApplicationInsights.DataContracts;
using Microsoft.ApplicationInsights.Extensibility;
using System.Linq;

namespace functionapp0915
{
    public class HttpTrigger2
    {
        private readonly TelemetryClient telemetryClient;

        /// Using dependency injection will guarantee that you use the same configuration for telemetry collected automatically and manually.
        public HttpTrigger2(TelemetryConfiguration telemetryConfiguration)
        {
            this.telemetryClient = new TelemetryClient(telemetryConfiguration);
        }

        [FunctionName("HttpTrigger2")]
        public Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)]
            HttpRequest req, ExecutionContext context, ILogger log)
        {
            log.LogInformation("C# HTTP trigger function processed a request.");
            DateTime start = DateTime.UtcNow;

            // Parse query parameter
            string name = req.Query
                .FirstOrDefault(q => string.Compare(q.Key, "name", true) == 0)
                .Value;

            // Write an event to the customEvents table.
            var evt = new EventTelemetry("Function called");
            evt.Context.User.Id = name;
            this.telemetryClient.TrackEvent(evt);

            // Generate a custom metric, in this case let's use ContentLength.
            this.telemetryClient.GetMetric("contentLength").TrackValue(req.ContentLength);

            // Log a custom dependency in the dependencies table.
            var dependency = new DependencyTelemetry
            {
                Name = "GET api/planets/1/",
                Target = "swapi.co",
                Data = "https://swapi.co/api/planets/1/",
                Timestamp = start,
                Duration = DateTime.UtcNow - start,
                Success = true
            };
            dependency.Context.User.Id = name;
            this.telemetryClient.TrackDependency(dependency);

            return Task.FromResult<IActionResult>(new OkResult());
        }
    }
}

Neste exemplo, os dados de métrica personalizados são agregados pelo host antes de serem enviados para a tabela customMetrics. Para saber mais, confira a documentação do GetMetric no Application Insights.

Ao executar localmente, você deve adicionar a configuração APPINSIGHTS_INSTRUMENTATIONKEY com a chave Application Insights ao arquivo APPINSIGHTS_INSTRUMENTATIONKEY.

Não chame TrackRequest nem StartOperation<RequestTelemetry>, pois você verá solicitações duplicadas de uma invocação de função. O runtime do Functions controla automaticamente as solicitações.

Não definir telemetryClient.Context.Operation.Id. Essa configuração global causa correlação incorreta quando muitas funções são executadas simultaneamente. Em vez disso, crie uma nova instância de telemetria (DependencyTelemetry, EventTelemetry) e modifique a propriedade Context. Em seguida, passe na instância de telemetria para o método Track correspondente em TelemetryClient (TrackDependency(), TrackEvent(), TrackMetric()). Esse método garante que a telemetria tenha os detalhes de correlação corretos para a invocação de função atual.

Funções de teste

Os seguintes artigos mostram como executar uma função de biblioteca de classes C# em processo localmente para fins de teste:

Variáveis de ambiente

Para obter uma variável de ambiente ou um valor de configuração do aplicativo, use System.Environment.GetEnvironmentVariable, conforme mostrado no exemplo de código a seguir:

public static class EnvironmentVariablesExample
{
    [FunctionName("GetEnvironmentVariables")]
    public static void Run([TimerTrigger("0 */5 * * * *")]TimerInfo myTimer, ILogger log)
    {
        log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");
        log.LogInformation(GetEnvironmentVariable("AzureWebJobsStorage"));
        log.LogInformation(GetEnvironmentVariable("WEBSITE_SITE_NAME"));
    }

    private static string GetEnvironmentVariable(string name)
    {
        return name + ": " +
            System.Environment.GetEnvironmentVariable(name, EnvironmentVariableTarget.Process);
    }
}

As configurações do aplicativo podem ser lidas de variáveis de ambiente ao desenvolver localmente e ao executar no Azure. Ao desenvolver localmente, as configurações do aplicativo são provenientes da coleção Values no arquivo Values. Em ambos os ambientes, local e do Azure, GetEnvironmentVariable("<app setting name>") recupera o valor da configuração de aplicativo nomeada. Por exemplo, quando você estivesse executando localmente, "Nome do Meu Site" seria retornado se o arquivo local.settings.json contivesse { "Values": { "WEBSITE_SITE_NAME": "My Site Name" } }.

A propriedade System.Configuration.ConfigurationManager.AppSettings é uma API alternativa para obter os valores de configuração do aplicativo, mas é recomendável que você use GetEnvironmentVariable conforme mostrado aqui.

Associando no runtime

No C# e em outras linguagens .NET, é possível usar um padrão de associação obrigatório em vez de associações declarativas em atributos. A associação obrigatória é útil quando os parâmetros de associação precisam ser calculado no runtime, em vez do tempo de design. Com esse padrão, é possível se vincular a associações de entrada e saída com suporte instantaneamente no código da função.

Defina uma associação obrigatória da seguinte maneira:

  • Não inclua um atributo em na assinatura de função para as associações obrigatórias desejadas.

  • Passe um parâmetro de entrada Binder binder ou IBinder binder.

  • Use o padrão de C# a seguir para realizar a associação de dados.

    using (var output = await binder.BindAsync<T>(new BindingTypeAttribute(...)))
    {
        ...
    }
    

    BindingTypeAttribute é o atributo do .NET que define a associação, e T é um tipo de entrada ou saída com suporte nesse tipo de associação. T não pode ser um tipo de parâmetro out (como out JObject). Por exemplo, a associação de saída de tabela dos Aplicativos Móveis dá suporte a seis tipos de saída, mas você só pode usar ICollector<T> ou IAsyncCollector<T> com a associação imperativa.

Exemplo de atributo único

O código de exemplo a seguir cria uma associação de saída do Armazenamento de Blobs com o caminho do blob definido em tempo de execução e grava uma cadeia de caracteres no blob.

public static class IBinderExample
{
    [FunctionName("CreateBlobUsingBinder")]
    public static void Run(
        [QueueTrigger("myqueue-items-source-4")] string myQueueItem,
        IBinder binder,
        ILogger log)
    {
        log.LogInformation($"CreateBlobUsingBinder function processed: {myQueueItem}");
        using (var writer = binder.Bind<TextWriter>(new BlobAttribute(
                    $"samples-output/{myQueueItem}", FileAccess.Write)))
        {
            writer.Write("Hello World!");
        };
    }
}

BlobAttribute define a associação de entrada ou saída do Armazenamento de Blobs e TextWriter é um tipo de associação de saída com suporte.

Exemplo de atributos múltiplos

O exemplo anterior obtém a configuração do aplicativo para a cadeia de conexão da conta de armazenamento principal do aplicativo de funções (que é AzureWebJobsStorage). É possível especificar uma configuração de aplicativo personalizada a ser usada para a conta de armazenamento adicionando StorageAccountAttribute e passando a matriz de atributos para BindAsync<T>(). Use um parâmetro Binder, não IBinder. Por exemplo:

public static class IBinderExampleMultipleAttributes
{
    [FunctionName("CreateBlobInDifferentStorageAccount")]
    public async static Task RunAsync(
            [QueueTrigger("myqueue-items-source-binder2")] string myQueueItem,
            Binder binder,
            ILogger log)
    {
        log.LogInformation($"CreateBlobInDifferentStorageAccount function processed: {myQueueItem}");
        var attributes = new Attribute[]
        {
        new BlobAttribute($"samples-output/{myQueueItem}", FileAccess.Write),
        new StorageAccountAttribute("MyStorageAccount")
        };
        using (var writer = await binder.BindAsync<TextWriter>(attributes))
        {
            await writer.WriteAsync("Hello World!!");
        }
    }
}

Gatilhos e associações

Esta tabela mostra as associações que são compatíveis com as versões principais do Azure Functions Runtime:

Tipo 1.x1 2.x e posterior2 Gatilho Entrada Saída
Armazenamento de Blobs
Azure Cosmos DB
Azure Data Explorer
SQL do Azure
Dapr4
Grade de Eventos
Hubs de Evento
HTTP e webhooks
Hub IoT
Kafka3
Aplicativos Móveis
Hubs de Notificação
Armazenamento de filas
Redis
RabbitMQ3
SendGrid
Barramento de Serviço
SignalR
Armazenamento de tabelas
Timer
Twilio

Observações:

  1. O suporte da versão 1.x do runtime do Azure Functions terminará em 14 de setembro de 2026. Recomendamos que você migre seus aplicativos para a versão 4.x para receber suporte completo.
  2. A partir do runtime da versão 2.x, todas as associações, exceto HTTP e Temporizador, devem ser registradas. Confira Registrar as extensões de associação.
  3. Não há suporte para gatilhos no plano de consumo. Requer gatilhos controlados por runtime.
  4. Tem suporte apenas no Kubernetes, no IoT Edge e em outros modos auto-hospedados.

Próximas etapas