Condividi tramite


Usare l'iniezione delle dipendenze nelle Funzioni Azure .NET

Azure Functions supporta il modello di progettazione software Dependency Injection (DI), una tecnica per ottenere l'inversione del controllo (IoC) tra le classi e le loro dipendenze.

  • L'inserimento delle dipendenze in Funzioni di Azure si basa sulle funzionalità di inserimento delle dipendenze di .NET Core. È consigliabile acquisire familiarità con la dependency injection di .NET Core. Esistono differenze nel modo in cui si esegue l'override delle dipendenze e come vengono letti i valori di configurazione con Funzioni di Azure nel piano a consumo.

  • Il supporto per l'inserimento delle dipendenze inizia con Funzioni di Azure 2.x.

  • I modelli di inserimento delle dipendenze variano a seconda che le funzioni C# vengano eseguite in-process o out-of-process.

Importante

Le indicazioni contenute in questo articolo si applicano solo alle funzioni della libreria di classi C#, eseguite in-process con il runtime. Questo modello personalizzato di inserimento delle dipendenze non si applica alle funzioni isolate .NET, che consente di eseguire funzioni .NET out-of-process. Il modello di processo di lavoro isolato .NET si basa sui normali modelli di inserimento delle dipendenze di ASP.NET Core. Per ulteriori informazioni, vedere Iniezione delle dipendenze nella guida al processo di lavoro isolato di .NET.

Prerequisiti

Prima di poter usare l'inserimento delle dipendenze, è necessario installare i pacchetti NuGet seguenti:

Registrare i servizi

Per registrare i servizi, creare un metodo per configurare e aggiungere componenti a un'istanza di IFunctionsHostBuilder. L'host di Funzioni di Azure crea un'istanza di IFunctionsHostBuilder e la passa direttamente nel metodo.

Avvertimento

Per le applicazioni di funzioni in esecuzione nei piani di consumo o Premium, le modifiche ai valori di configurazione usati nei trigger possono causare errori di ridimensionamento. Qualsiasi modifica apportata a queste proprietà dalla classe FunctionsStartup comporta un errore di avvio dell'applicazione di funzioni.

L'inserimento di IConfiguration può causare comportamenti imprevisti. Per altre informazioni sull'aggiunta di origini di configurazione, vedere Personalizzazione delle origini di configurazione.

Per registrare il metodo, aggiungere l'attributo assembly che specifica il nome del tipo usato durante l'avvio FunctionsStartup .

using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;

[assembly: FunctionsStartup(typeof(MyNamespace.Startup))]

namespace MyNamespace;

public class Startup : FunctionsStartup
{
    public override void Configure(IFunctionsHostBuilder builder)
    {
        builder.Services.AddHttpClient();

        builder.Services.AddSingleton<IMyService>((s) => {
            return new MyService();
        });

        builder.Services.AddSingleton<ILoggerProvider, MyLoggerProvider>();
    }
}

In questo esempio viene usato il pacchetto Microsoft.Extensions.Http necessario per registrare un oggetto all'avvio HttpClient .

Avvertenze

Una serie di passaggi di registrazione vengono eseguiti prima e dopo che il runtime elabora la classe di avvio. Tenere quindi presenti gli elementi seguenti:

  • La classe di avvio è destinata solo alla configurazione e alla registrazione. Evitare di usare i servizi registrati all'avvio durante il processo di avvio. Ad esempio, non provare a registrare un messaggio in un logger registrato durante l'avvio. Questo punto del processo di registrazione è troppo presto perché i servizi siano disponibili per l'uso. Dopo l'esecuzione del Configure metodo, il runtime di Funzioni continua a registrare altre dipendenze, che possono influire sul funzionamento dei servizi.

  • Il contenitore di inserimento delle dipendenze contiene solo tipi registrati in modo esplicito. Gli unici servizi disponibili come tipi iniettabili sono gli elementi configurati nel Configure metodo . Di conseguenza, i tipi specifici di Funzioni come BindingContext e ExecutionContext non sono disponibili durante l'installazione o come tipi iniettabili.

  • La configurazione dell'autenticazione ASP.NET non è supportata. L'host delle funzioni configura i servizi di autenticazione di ASP.NET per esporre correttamente le API per le operazioni di base del ciclo di vita. Altre configurazioni in una classe personalizzata Startup possono eseguire l'override di questa configurazione, causando conseguenze impreviste. Ad esempio, la chiamata builder.Services.AddAuthentication() può interrompere l'autenticazione tra il portale e l'host, causando messaggi come il runtime di Funzioni di Azure non è raggiungibile.

Utilizzare le dipendenze iniettate

L'iniezione del costruttore viene utilizzata per rendere disponibili le tue dipendenze in una funzione. L'uso dell'inserimento del costruttore richiede che non si usino classi statiche per i servizi inseriti o per le classi di funzioni.

L'esempio seguente illustra come le IMyService dipendenze e HttpClient vengono inserite in una funzione attivata da HTTP.

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

namespace MyNamespace;

public class MyHttpTrigger
{
    private readonly HttpClient _client;
    private readonly IMyService _service;

    public MyHttpTrigger(IHttpClientFactory httpClientFactory, IMyService service)
    {
        this._client = httpClientFactory.CreateClient();
        this._service = service;
    }

    [FunctionName("MyHttpTrigger")]
    public async Task<IActionResult> Run(
        [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
        ILogger log)
    {
        var response = await _client.GetAsync("https://microsoft.com");
        var message = _service.GetMessage();

        return new OkObjectResult("Response from function with injected dependencies.");
    }
}

In questo esempio viene usato il pacchetto Microsoft.Extensions.Http necessario per registrare un oggetto all'avvio HttpClient .

Durata del servizio

Le app di Azure Functions offrono la stessa durata del servizio dell'Iniezione di Dipendenze di ASP.NET. Per un'app per le funzioni, le diverse durate del servizio si comportano nel modo seguente:

  • Temporaneo: i servizi temporanei vengono creati in ogni risoluzione del servizio.
  • Ambito: la durata del servizio con ambito corrisponde a quella di esecuzione di una funzione. I servizi con ambito vengono creati una volta per ogni esecuzione di funzione. Le richieste successive per tale servizio durante l'esecuzione riutilizzano l'istanza del servizio esistente.
  • Singleton: la durata del servizio singleton corrisponde alla durata dell'host e viene riutilizzata tra le esecuzioni di funzioni in tale istanza. I servizi di durata Singleton sono consigliati per connessioni e client, come ad esempio DocumentClient o le HttpClient istanze.

Visualizzare o scaricare un esempio di durata del servizio diversa in GitHub.

Servizi di registrazione

Se hai bisogno di un provider di gestione dei log personalizzato, registra un tipo personalizzato come istanza di ILoggerProvider, disponibile tramite il pacchetto NuGet Microsoft.Extensions.Logging.Abstractions.

Application Insights viene aggiunto automaticamente da Funzioni di Azure.

Avvertimento

  • Non aggiungere AddApplicationInsightsTelemetry() alla raccolta di servizi, che registra i servizi in conflitto con i servizi forniti dall'ambiente.
  • Non registrare il proprio TelemetryConfiguration o TelemetryClient se si usa la funzionalità predefinita di Application Insights. Se è necessario configurare la propria TelemetryClient istanza, crearne una tramite l'inserimento TelemetryConfiguration come illustrato in Registrare dati di telemetria personalizzati nelle funzioni C#.

ILogger<T> e ILoggerFactory

L'host inserisce servizi ILogger<T> e ILoggerFactory nei costruttori. Tuttavia, per impostazione predefinita, questi nuovi filtri di registrazione vengono filtrati dai log delle funzioni. È necessario modificare il host.json file per acconsentire esplicitamente a filtri e categorie aggiuntivi.

Nell'esempio seguente viene illustrato come aggiungere un oggetto ILogger<HttpTrigger> con i log esposti all'host.

namespace MyNamespace;

public class HttpTrigger
{
    private readonly ILogger<HttpTrigger> _log;

    public HttpTrigger(ILogger<HttpTrigger> log)
    {
        _log = log;
    }

    [FunctionName("HttpTrigger")]
    public async Task<IActionResult> Run(
        [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req)
    {
        _log.LogInformation("C# HTTP trigger function processed a request.");

        // ...
}

Il file di esempio host.json seguente aggiunge il filtro di log.

{
    "version": "2.0",
    "logging": {
        "applicationInsights": {
            "samplingSettings": {
                "isEnabled": true,
                "excludedTypes": "Request"
            }
        },
        "logLevel": {
            "MyNamespace.HttpTrigger": "Information"
        }
    }
}

Per altre informazioni sui livelli di log, vedere Configurare i livelli di log.

Servizi forniti dall'app di funzioni

L'host della funzione registra molti servizi. I servizi seguenti sono sicuri da accettare come dipendenza nell'applicazione:

Tipo di servizio Durata della vita Descrizione
Microsoft.Extensions.Configuration.IConfiguration Singleton Configurazione del runtime
Microsoft.Azure.WebJobs.Host.Executors.IHostIdProvider Singleton Responsabile della fornitura dell'ID dell'istanza host

Se sono presenti altri servizi da cui si vuole prendere una dipendenza, creare un problema e proporli in GitHub.

Sovrascrittura dei servizi host

La sostituzione dei servizi forniti dall'host non è attualmente supportata. Se sono presenti servizi di cui si vuole eseguire l'override, creare un problema e proporli in GitHub.

Utilizzo di opzioni e impostazioni

I valori definiti nelle impostazioni dell'app sono disponibili in un'istanzaIConfiguration, che consente di leggere i valori delle impostazioni dell'app nella classe di avvio.

È possibile estrarre valori dall'istanza IConfiguration in un tipo personalizzato. La copia dei valori delle impostazioni dell'app in un tipo personalizzato semplifica il test dei servizi rendendo questi valori iniettabili. Le impostazioni lette nell'istanza di configurazione devono essere coppie chiave/valore semplici. Per le funzioni in esecuzione in un piano Elastic Premium, i nomi delle impostazioni dell'applicazione possono contenere solo lettere, numeri (0-9), punti (.), punti (:) e caratteri di sottolineatura (_). Per altre informazioni, vedere Considerazioni sull'impostazione dell'app.

Si consideri la classe seguente che include una proprietà denominata coerente con un'impostazione dell'app:

public class MyOptions
{
    public string MyCustomSetting { get; set; }
}

E un local.settings.json file che potrebbe strutturare l'impostazione personalizzata come segue:

{
  "IsEncrypted": false,
  "Values": {
    "MyOptions:MyCustomSetting": "Foobar"
  }
}

Dall'interno del Startup.Configure metodo è possibile estrarre valori dall'istanza IConfiguration nel tipo personalizzato usando il codice seguente:

builder.Services.AddOptions<MyOptions>()
    .Configure<IConfiguration>((settings, configuration) =>
    {
        configuration.GetSection("MyOptions").Bind(settings);
    });

La chiamata di Bind copia i valori con nomi di proprietà corrispondenti dalla configurazione all'istanza personalizzata. L'istanza delle opzioni è ora disponibile nel contenitore IoC da inserire in una funzione.

L'oggetto options viene inserito nella funzione come istanza dell'interfaccia generica IOptions . Usare la Value proprietà per accedere ai valori trovati nella configurazione.

using System;
using Microsoft.Extensions.Options;

public class HttpTrigger
{
    private readonly MyOptions _settings;

    public HttpTrigger(IOptions<MyOptions> options)
    {
        _settings = options.Value;
    }
}

Per altre informazioni, vedere Modello di opzioni in ASP.NET Core.

Uso dei segreti utente di ASP.NET Core

Quando si sviluppa l'app in locale, ASP.NET Core fornisce uno strumento Secret Manager che consente di archiviare informazioni segrete all'esterno della radice del progetto. Rende meno probabile che i segreti vengano accidentalmente inseriti nel controllo del codice sorgente. Azure Functions Core Tools (versione 3.0.3233 o successiva) legge automaticamente i segreti creati da ASP.NET Core Secret Manager.

Per configurare un progetto di Funzioni di Azure .NET per l'uso dei segreti utente, eseguire il comando seguente nella radice del progetto.

dotnet user-secrets init

Usare quindi il dotnet user-secrets set comando per creare o aggiornare i segreti.

dotnet user-secrets set MySecret "my secret value"

Per accedere ai valori dei segreti utente nel codice dell'app per le funzioni, usare IConfiguration o IOptions.

Personalizzazione delle origini di configurazione

Per indicare altre origini di configurazione, eseguire l'override del metodo ConfigureAppConfiguration nella classe dell'applicazione delle funzioni StartUp.

L'esempio seguente aggiunge valori di configurazione sia dai file di impostazioni dell'app di base che da quello facoltativo specifico dell'ambiente.

using System.IO;
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

[assembly: FunctionsStartup(typeof(MyNamespace.Startup))]

namespace MyNamespace;

public class Startup : FunctionsStartup
{
    public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
    {
        FunctionsHostBuilderContext context = builder.GetContext();

        builder.ConfigurationBuilder
            .AddJsonFile(Path.Combine(context.ApplicationRootPath, "appsettings.json"), optional: true, reloadOnChange: false)
            .AddJsonFile(Path.Combine(context.ApplicationRootPath, $"appsettings.{context.EnvironmentName}.json"), optional: true, reloadOnChange: false)
            .AddEnvironmentVariables();
    }
    
    public override void Configure(IFunctionsHostBuilder builder)
    {
    }
}

Aggiungere fornitori di configurazione alla proprietà ConfigurationBuilder di IFunctionsConfigurationBuilder. Per altre informazioni sull'uso dei provider di configurazione, vedere Configurazione in ASP.NET Core.

Un FunctionsHostBuilderContext oggetto viene ottenuto da IFunctionsConfigurationBuilder.GetContext(). Usare questo contesto per recuperare il nome dell'ambiente corrente e risolvere il percorso dei file di configurazione nella cartella dell'app per le funzioni.

Per impostazione predefinita, i file di configurazione, appsettings.json ad esempio, non vengono copiati automaticamente nella cartella di output dell'app per le funzioni. Aggiornare il .csproj file in modo che corrisponda all'esempio seguente per assicurarsi che i file vengano copiati.

<None Update="appsettings.json">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>      
</None>
<None Update="appsettings.Development.json">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    <CopyToPublishDirectory>Never</CopyToPublishDirectory>
</None>

Passaggi successivi

Per altre informazioni, vedere le risorse seguenti: