Partager via


Utiliser l’injection de dépendances dans .NET Azure Functions

Azure Functions prend en charge le modèle de conception logicielle d’injection de dépendances (DI), qui est une technique permettant d’obtenir l’inversion du contrôle (IoC) entre les classes et leurs dépendances.

  • L’injection de dépendances dans Azure Functions repose sur les fonctionnalités d’injection de dépendances .NET Core. La connaissance de l’injection de dépendances .NET Core est recommandée. Il existe des différences dans la façon dont vous remplacez les dépendances et la façon dont les valeurs de configuration sont lues avec Azure Functions sur le plan Consommation.

  • La prise en charge de l’injection de dépendances commence par Azure Functions 2.x.

  • Les modèles d’injection de dépendances diffèrent selon que vos fonctions C# s’exécutent en cours ou hors processus.

Important

Les instructions de cet article s’appliquent uniquement aux fonctions de bibliothèque de classes C#, qui s’exécutent en cours avec le runtime. Ce modèle d’injection de dépendance personnalisé ne s’applique pas aux fonctions isolées .NET, ce qui vous permet d’exécuter des fonctions .NET hors processus. Le modèle de processus worker isolé .NET s’appuie sur des modèles d’injection de dépendances standard ASP.NET Core. Pour plus d’informations, consultez l’injection de dépendances dans le guide de processus de travail isolé .NET.

Conditions préalables

Avant de pouvoir utiliser l’injection de dépendances, vous devez installer les packages NuGet suivants :

Enregistrer des services

Pour inscrire des services, créez une méthode pour configurer et ajouter des composants à une IFunctionsHostBuilder instance. L’hôte Azure Functions crée une instance de IFunctionsHostBuilder et la transmet directement à votre méthode.

Avertissement

Pour les applications de fonction s’exécutant dans les plans Consommation ou Premium, les modifications apportées aux valeurs de configuration utilisées dans les déclencheurs peuvent entraîner des erreurs de mise à l’échelle. Toute modification apportée à ces propriétés par la FunctionsStartup classe entraîne une erreur de démarrage de l’application de fonction.

L’injection de IConfiguration peut entraîner un comportement inattendu. Pour en savoir plus sur l’ajout de sources de configuration, consultez Personnalisation des sources de configuration.

Pour inscrire la méthode, ajoutez l’attribut FunctionsStartup d’assembly qui spécifie le nom de type utilisé au démarrage.

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

Cet exemple utilise le package Microsoft.Extensions.Http requis pour inscrire un HttpClient package au démarrage.

Mises en garde

Une série d’étapes d’enregistrement s’exécutent avant et après que le runtime traite la classe de démarrage. Par conséquent, gardez à l’esprit les éléments suivants :

  • La classe de démarrage est destinée uniquement à l’installation et à l’inscription. Évitez d’utiliser des services inscrits au cours du processus de démarrage. Par exemple, n’essayez pas de consigner un message dans un enregistreur d’événements inscrit lors du démarrage. Ce point du processus d’inscription est trop tôt pour que vos services soient disponibles pour une utilisation. Une fois la Configure méthode exécutée, le runtime Functions continue d’inscrire d’autres dépendances, ce qui peut affecter le fonctionnement de vos services.

  • Le conteneur d’injection de dépendances contient uniquement les types inscrits explicitement. Les seuls services disponibles en tant que types injectables sont définis dans la Configure méthode. Par conséquent, les types spécifiques à Functions comme BindingContext et ExecutionContext ne sont pas disponibles lors de la configuration ou en tant que types injectables.

  • La configuration de l’authentification ASP.NET n’est pas prise en charge. L'hôte Functions configure les services d’authentification ASP.NET pour exposer correctement les API pour les opérations essentielles du cycle de vie. D’autres configurations d’une classe personnalisée Startup peuvent remplacer cette configuration, ce qui entraîne des conséquences inattendues. Par exemple, un appel à builder.Services.AddAuthentication() peut interrompre l’authentification entre le portail et l’hôte, menant à des messages tels que le runtime Azure Functions est inaccessible.

Utiliser des dépendances injectées

L’injection de constructeur est utilisée pour rendre vos dépendances disponibles dans une fonction. L’utilisation de l’injection de constructeur nécessite que vous n’utilisiez pas de classes statiques pour les services injectés ou pour vos classes fonctionnelles.

L'exemple suivant démontre comment les dépendances IMyService et HttpClient sont injectées dans une fonction déclenchée par 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.");
    }
}

Cet exemple utilise le package Microsoft.Extensions.Http requis pour inscrire un HttpClient package au démarrage.

Durées de vie des services

Les durées de service des applications Azure Functions sont identiques à celles du service d’injection de dépendance ASP.NET. Pour une application Functions, les différentes durées de vie des services se comportent comme suit :

  • Temporaire : des services temporaires sont créés à chaque résolution du service.
  • Étendu : la durée de vie du service étendu correspond à celle d’exécution de la fonction. Les services délimités sont créés une fois par exécution de fonction. Les demandes ultérieures de ce service pendant l’exécution réutilisent l’instance de service existante.
  • Singleton : la durée de vie du service singleton correspond à la durée de vie de l’hôte et est réutilisée entre les exécutions de fonction sur cette instance. Les services à durée de vie singleton sont recommandés pour des connexions et des clients, par exemple, pour des instances DocumentClient ou HttpClient.

Affichez ou téléchargez un exemple de durée de vie de service différente sur GitHub.

Services de journalisation

Si vous avez besoin de votre propre fournisseur de journalisation, enregistrez un type personnalisé en tant qu'instance de ILoggerProvider, disponible via le package NuGet Microsoft.Extensions.Logging.Abstractions.

Application Insights est ajouté automatiquement par Azure Functions.

Avertissement

  • N’ajoutez AddApplicationInsightsTelemetry() pas à la collection de services, qui inscrit les services qui entrent en conflit avec les services fournis par l’environnement.
  • N’inscrivez pas votre propre TelemetryConfiguration ou TelemetryClient si vous utilisez la fonctionnalité Application Insights intégrée. Si vous devez configurer votre propre TelemetryClient instance, créez-en une via l'objet injecté TelemetryConfiguration, comme indiqué dans Consigner la télémétrie personnalisée dans les fonctions C#.

ILogger<T> et ILoggerFactory

L'hôte injecte les services ILogger<T> et ILoggerFactory dans des constructeurs. Toutefois, par défaut, ces nouveaux filtres de journalisation sont filtrés hors des journaux de fonction. Vous devez modifier le host.json fichier pour choisir des filtres et des catégories supplémentaires.

L’exemple suivant montre comment ajouter un ILogger<HttpTrigger> avec les journaux qui sont exposés à l’hôte.

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.");

        // ...
}

L’exemple host.json de fichier suivant ajoute le filtre de journal.

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

Pour plus d’informations sur les niveaux de journal, consultez Configurer les niveaux de journal.

Services fournis par Function App

L’hôte de la fonction inscrit de nombreux services. Les services suivants sont sûrs à utiliser comme dépendance dans votre application :

Type de service Durée de vie Descriptif
Microsoft.Extensions.Configuration.IConfiguration Singleton Configuration du runtime
Microsoft.Azure.WebJobs.Host.Executors.IHostIdProvider Singleton Responsable de la fourniture de l’ID de l’instance hôte

Si vous souhaitez utiliser d’autres services, créez un problème et proposez-les sur GitHub.

Remplacement des services de l’hôte

Le remplacement des services fournis par l’hôte n’est pas pris en charge actuellement. S’il existe des services que vous souhaitez remplacer, créez un problème et proposez-les sur GitHub.

Utilisation des options et des paramètres

Les valeurs définies dans les paramètres d’application sont disponibles dans une IConfiguration instance, ce qui vous permet de lire les valeurs des paramètres d’application dans la classe de démarrage.

Vous pouvez extraire des valeurs de l’instance IConfiguration dans un type personnalisé. La copie des valeurs des paramètres d’application dans un type personnalisé facilite le test de vos services en rendant ces valeurs injectables. Les paramètres lus dans l’instance de configuration doivent être des paires clé/valeur simples. Pour les fonctions exécutées dans un plan Elastic Premium, les noms des paramètres d’application ne peuvent contenir que des lettres, des chiffres (0-9), des points (), des points (.:) et des traits de soulignement (_). Pour plus d’informations, consultez considérations relatives au paramètre d’application.

Considérez la classe suivante qui inclut une propriété nommée cohérente avec un paramètre d’application :

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

Et un local.settings.json fichier qui peut structurer le paramètre personnalisé comme suit :

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

À partir de la Startup.Configure méthode, vous pouvez extraire des valeurs de l’instance IConfiguration dans votre type personnalisé à l’aide du code suivant :

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

L’appel de Bind copie les valeurs dont les noms de propriétés correspondent à ceux de la configuration dans l’instance personnalisée. L’instance d’options est désormais disponible dans le conteneur IoC pour injecter dans une fonction.

L’objet options est injecté dans la fonction en tant qu’instance de l’interface générique IOptions . Utilisez la Value propriété pour accéder aux valeurs trouvées dans votre configuration.

using System;
using Microsoft.Extensions.Options;

public class HttpTrigger
{
    private readonly MyOptions _settings;

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

Pour plus d’informations, consultez le modèle Options dans ASP.NET Core.

Utilisation de secrets utilisateur ASP.NET Core

Lorsque vous développez votre application localement, ASP.NET Core fournit un outil Secret Manager qui vous permet de stocker des informations secrètes en dehors de la racine du projet. Le risque que les secrets soient accidentellement confiés au contrôle de code source est ainsi moins grand. Azure Functions Core Tools (version 3.0.3233 ou ultérieure) lit automatiquement les secrets créés par l’ASP.NET Core Secret Manager.

Pour configurer un projet Azure Functions .NET pour utiliser des secrets utilisateur, exécutez la commande suivante dans la racine du projet.

dotnet user-secrets init

Utilisez ensuite la dotnet user-secrets set commande pour créer ou mettre à jour des secrets.

dotnet user-secrets set MySecret "my secret value"

Pour accéder aux valeurs de secrets utilisateur dans le code de votre application de fonction, utilisez IConfiguration ou IOptions.

Personnalisation des sources de configuration

Pour spécifier d’autres sources de configuration, remplacez la méthode ConfigureAppConfiguration dans la classe StartUp de votre application de fonction.

L'exemple suivant ajoute des valeurs de configuration à partir de fichiers de paramètres d'application de base et facultatifs, spécifiques à l'environnement.

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

Ajoutez des fournisseurs de configuration à la ConfigurationBuilder propriété de IFunctionsConfigurationBuilder. Pour plus d’informations sur l’utilisation de fournisseurs de configuration, consultez Configuration dans ASP.NET Core.

A FunctionsHostBuilderContext est obtenu à partir de IFunctionsConfigurationBuilder.GetContext(). Utilisez ce contexte pour récupérer le nom actuel de l’environnement et résoudre l’emplacement des fichiers de configuration dans le dossier de votre application de fonction.

Par défaut, les fichiers de configuration tels que appsettings.json ne sont pas copiés automatiquement dans le dossier de sortie de l’application de fonction. Mettez à jour votre .csproj fichier pour qu’il corresponde à l’exemple suivant pour vous assurer que les fichiers sont copiés.

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

Étapes suivantes

Pour plus d’informations, consultez les ressources suivantes :