3
votes

Utilisation de ConfigurationBuilder dans FunctionsStartup

J'ai une fonction Azure et j'utilise le système DI pour enregistrer certains types; par exemple:

IConfiguration config = new ConfigurationBuilder()
   .SetBasePath(context.FunctionAppDirectory)
   .AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
   .AddEnvironmentVariables()
   .Build();

Cependant, je devais également enregistrer certaines données de mes paramètres d'environnement. À l'intérieur de la fonction elle-même, je peux obtenir le ExecutionContext , et je peux donc le faire:

public class Startup : FunctionsStartup
{
    public override void Configure(IFunctionsHostBuilder builder)
    {
        builder.Services
            .AddTransient<IMyInterface, MyClass>()
    . . . etc

Cependant, dans FunctionsStartup, je n'ai pas accès à ExecutionContext . Existe-t-il un moyen d'obtenir l'ExecutionContext de la classe FunctionsStartup ou, alternativement, un autre moyen de déterminer le répertoire en cours d'exécution, afin que je puisse définir le chemin de base?


1 commentaires

Peut-être que cela pourrait vous aider. github.com/Azure/azure-webjobs-sdk/issues/…


4 Réponses :


2
votes

Vous n'avez besoin d'aucun objet de configuration dans Azure Functions (v2). Tous les paramètres de l'application sont injectés en tant que variables d'environnement. Ainsi, vous pouvez faire juste un simple Environment.GetEnvironmentVariable()

Lors de l'exécution locale, le local.settings.json est lu de la même manière.

voir ici: https://docs.microsoft.com/en-us/sandbox/functions-recipes/environment-variables?tabs=csharp


3 commentaires

Êtes-vous en train de dire que builder.Services.Configure est désormais redondant?


pas pour DI en général, mais vous n'en avez pas besoin pour lire les paramètres de l'application.


Assurez-vous simplement que pour local.settings.json , vos paramètres se local.settings.json dans la section Values :



0
votes

Malheureusement, à l'heure actuelle, il n'existe aucun moyen standard d'obtenir le répertoire local en cours d'exécution. Ce serait mieux si ExecutionContext ou quelque chose de similaire exposait cela.

En l'absence de méthode standard, AzureWebJobsScriptRoot la variable d'environnement AzureWebJobsScriptRoot pour obtenir le répertoire de travail actuel, mais cela ne fonctionne que localement. Dans l'environnement Azure, j'utilise Environment.GetEnvironmentVariable("HOME")}\\site\\wwwroot .

J'ai publié un code pour cela en réponse à une question similaire ici: Azure Functions, comment avoir plusieurs fichiers de configuration .json

Il existe également une solution similaire à ce problème de github .


3 commentaires

L'objet ExecutionContext est disponible dans votre fonction si vous en avez besoin: github.com/Azure/azure-functions-host/wiki / ...


@silent Est-il disponible lorsque la classe de démarrage est en cours d'exécution?


@Turbo jetez un œil à la réponse que j'ai fournie ci-dessus.



1
votes

Il existe un moyen solide de le faire, répondu ici: Obtenez le répertoire racine d'Azure Function App v2

Le fait que les applications de fonction utilisent des variables d'environnement comme moyen typique d'obtenir la configuration n'est, bien que vrai, pas optimal IMO. La possibilité d'acquérir un fichier appsettings.json en plus des éléments qui méritent d'être des variables d'environnement a sa place.

Le nombre de variables d'environnement définies via la tâche DevOps: l'option «Azure App Service Deploy» «Paramètres d'application et de configuration»> «Paramètres d'application» devient complètement incontrôlable.

Voici ma mise en œuvre au moment de la rédaction de cet article:

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "DefaultEndpointsProtocol=https;AccountName=<accountname>;AccountKey=<accountkey>;EndpointSuffix=core.windows.net",
    "Strickland:Propane:Config": "Dammit, Bobby!"
  }
}

Cela me permet d'exploiter mes variables de processus de publication pour effectuer une "substitution de variable JSON" spécifique à l'environnement pour la majeure partie de ma configuration, qui se trouve dans un appsettings.json bien structuré qui est défini sur Copier toujours. Notez que le chargement de appsettings.json est défini sur non facultatif (le paramètre false), tandis que les paramètres locaux et les secrets sont définis sur facultatifs pour s'adapter au développement local.

appsettings.json peut alors être formaté correctement et structuré comme ceci. Libérez les variables nommées correctement, par exemple "MyConfig.Setting" remplacera la valeur correctement si vous configurez votre version pour faire une substitution de variable JSON.

{
  "Environment": "dev",
  "APPINSIGHTS_INSTRUMENTATIONKEY": "<guid>",
  "MyConfig": {
    "Setting": "foo-bar-baz"
  }
}

Alors que local.settings.json reste dans le style plat:

ExecutionContextOptions executionContextOptions = builder.Services.BuildServiceProvider().GetService<IOptions<ExecutionContextOptions>>().Value;

IConfigurationBuilder configurationBuilder = new ConfigurationBuilder()
    .SetBasePath(executionContextOptions.AppDirectory)
    .AddEnvironmentVariables()
    .AddJsonFile("appsettings.json", false)
    .AddJsonFile("local.settings.json", true)
    .AddUserSecrets(Assembly.GetExecutingAssembly(), true);

En outre, j'ai défini certains paramètres d'application (vars env) sur Azure KeyVault References dans le processus de publication, ainsi que les paramètres minimum requis pour que l'exécution d'Azure Function démarre correctement et communique correctement avec les métriques en direct App Insights.

J'espère que cela aidera quelqu'un qui, comme moi, déteste la masse sans cesse croissante d'éléments -Variable.Name "$ (ReleaseVariableName)" dans les paramètres de l'application. :)


0 commentaires

0
votes

Bien que la réponse vérifiée à cette question soit correcte, j'ai pensé qu'elle manquait de profondeur quant à la raison. La première chose que vous devez savoir est que sous les couvertures, une fonction Azure utilise le même ConfigurationBuilder que celui trouvé dans une application ASP.NET Core mais avec un ensemble différent de fournisseurs. Contrairement à ASP.NET Core qui est extrêmement bien documenté ( https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/ ), ce n'est pas le cas pour Azure Functions.

Pour comprendre cet ensemble de fournisseurs, vous pouvez placer la ligne de code suivante dans la méthode Configure (IFunctionsHostBuilder builder) de votre classe FunctionStartup ,

public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
{
    FunctionsHostBuilderContext context = builder.GetContext();

    builder.ConfigurationBuilder
        .SetBasePath(context.ApplicationRootPath)
        .AddJsonFile("appsettings.json", optional: true, reloadOnChange: false)
        .AddJsonFile($"appsettings.{context.EnvironmentName}.json", optional: true, reloadOnChange: false)
        .AddUserSecrets(Assembly.GetExecutingAssembly(), true, true)
        .AddEnvironmentVariables();
}

placez un point d'arrêt de débogage après la commande, exécutez votre fonction en mode débogage et effectuez un Quick Watch… sur la variable de configuration (cliquez avec le bouton droit sur le nom de la variable pour sélectionner Quick Watch…).

Le résultat de cette plongée dans l'exécution du code est la liste suivante de fournisseurs.

ExecutionContextOptions executionContextOptions = builder.Services.BuildServiceProvider().GetService<IOptions<ExecutionContextOptions>>().Value;

IConfigurationBuilder configurationBuilder = new ConfigurationBuilder()
    .SetBasePath(executionContextOptions.AppDirectory)
    .AddEnvironmentVariables()
    .AddJsonFile("appsettings.json", false)
    .AddJsonFile("local.settings.json", true)
    .AddUserSecrets(Assembly.GetExecutingAssembly(), true);

Le ChainedConfigurationProvider ajoute une IConfiguration existante en tant que source. Dans le cas de la configuration par défaut, ajoute la configuration de l'hôte et la définit comme première source pour la configuration de l'application.

Le premier MemoryConfigurationProvider ajoute la clé / valeur {[AzureWebJobsConfigurationSection, AzureFunctionsJobHost]} . Au moins, il le fait dans l'environnement de développement. Au moment où j'écris ceci, je ne trouve aucune documentation sur le but de ce MemoryConfigurationProvider ou AzureWebJobsConfigurationSection .

Le HostJsonFileConfigurationProvider est un autre de ceux sous les couvertures des fournisseurs non documentés, mais en regardant la documentation sur host.json ( https://docs.microsoft.com/en-us/azure/azure-functions/functions-host-json ) il semble être responsable de l'extraction de ces métadonnées.

Le JsonConfigurationProvider pour appsettings.json semble être une corrélation évidente avec l'utilisation par ASP.NET Core de appsettings.json, sauf pour une chose qui est que cela ne fonctionne pas. Après quelques recherches, j'ai trouvé que la racine du fournisseur de fichiers source n'était pas définie sur le dossier racine des applications où se trouve le fichier, mais plutôt sur un dossier AppData obscur (C: \ Users% USERNANE% \ AppData \ Local \ AzureFunctionsTools \ Releases \ 3.15.0 \ cli_x64). Aller pêcher.

EnvironmentVariablesConfigurationProvider charge les paires clé-valeur de variable d'environnement.

Le deuxième MemoryConfigurationProvider ajoute la clé / valeur {[AzureFunctionsJobHost: logging: console: isEnabled, false]} . Au moins, il le fait dans l'environnement de développement. Encore une fois, au moment où j'écris ceci, je ne trouve aucune documentation sur le but de ce MemoryConfigurationProvider ou AzureFunctionsJobHost .

Maintenant, la chose intéressante qui doit être soulignée est qu'il n'y a aucune mention de local.settings.json dans la configuration. C'est parce que local.settings.json ne fait PAS partie du processus ConfigurationBuilder . Au lieu de cela, local.settings.json fait partie d'Azure Functions Core Tools qui vous permet de développer et de tester vos fonctions sur votre ordinateur local ( https://docs.microsoft.com/en-us/azure/azure-functions/functions-run- local ). Les outils Azure Function Core se concentrent uniquement sur des sections et des clés / valeurs spécifiques telles que IsEncrypted , les sections Values et ConnectionString , etc., comme défini dans la documentation ( https://docs.microsoft.com/en-us/azure/azure-functions / functions-run-local # local-settings-file ). Ce qui arrive à ces clés / valeurs est également unique. Par exemple, les clés / valeurs de la section Valeurs sont insérées dans l'environnement en tant que variables. La plupart des développeurs ne remarquent même pas que local.settings.json est défini par défaut pour être ignoré par Git, ce qui rend également problématique si vous supprimez le référentiel de votre environnement de développement uniquement pour le restaurer ultérieurement. Quelque chose que ASP.NET Core a corrigé avec les secrets d'application ( https://docs.microsoft.com/en-us/aspnet/core/security/app-secrets ).

Alors, que se passe-t-il si nous créons notre propre configuration avec ConfigurationBuilder comme suggéré dans la question d'origine

IConfiguration config = new ConfigurationBuilder()
   .SetBasePath(context.FunctionAppDirectory)
   .AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
   .AddEnvironmentVariables()
   .Build();

ou en utilisant l'exemple montré dans l'une des autres réponses?

Microsoft.Extensions.Configuration.ChainedConfigurationProvider
MemoryConfigurationProvider
HostJsonFileConfigurationProvider
JsonConfigurationProvider for 'appsettings.json' (Optional)
EnvironmentVariablesConfigurationProvider
MemoryConfigurationProvider

Voici quelques-uns des problèmes rencontrés avec les deux exemples.

  • Le deuxième exemple est mal ordonné car AddEnvironmentVariables doit venir en dernier.

  • Aucun des exemples ne mentionne la nécessité de la ligne de code suivante. Élément de liste

    builder.Services.AddSingleton<IConfiguration>(configurationBuilder.Build());

    Sans cette ligne, la configuration n'existe que dans la méthode Configure (IFunctionsHostBuilder builder) de votre classe FunctionStartup . Cependant, avec la ligne, vous remplacez la configuration de votre build Azure Function sous les couvertures. Ce n'est pas nécessairement une bonne chose car vous n'avez aucun moyen de remplacer des fournisseurs tels que HostJsonFileConfigurationProvider .

  • La lecture du fichier local.settings.json ( .AddJsonFile ("appsettings.json") ) ne placera PAS les paires clé / valeur de la section Valeurs dans la configuration en tant que paires clé / valeur individuelles comme prévu, mais les regroupera sous les valeurs section. En d'autres termes, si par exemple vous souhaitez accéder à {["AzureWebJobsStorage": ""]} dans Values, vous pouvez utiliser la commande configuration.GetValue ("Values: AzureWebJobsStorage") . Le problème est qu'Azure s'attend à y accéder par le nom de clé «AzureWebJobsStorage» . Plus intéressant encore, étant donné que local.settings.json n'a jamais fait partie du processus ConfigurationBuilder , ceci est redondant car Azure Functions Core Tools a déjà placé ces valeurs dans l'environnement. La seule chose que cela fera est de vous permettre d'accéder aux sections et clés / valeurs non définies dans le cadre de local.settings.json ( https://docs.microsoft.com/en-us/azure/azure-functions/functions-run -local # fichier-paramètres-locaux ). Mais pourquoi voudriez-vous extraire des valeurs de configuration d'un fichier qui ne sera pas copié dans votre code de production?

Tout cela nous amène à un meilleur moyen d'affecter les modifications de la configuration sans détruire la configuration par défaut créée par Azure Function qui consiste à remplacer la méthode ConfigureAppConfiguration dans votre classe FunctionStartup ( https://docs.microsoft.com/en-us/ azure / azure-functions / functions-dotnet-dependency-injection # customizing-configuration-sources ).

L'exemple suivant va encore plus loin dans celui fourni dans la documentation en ajoutant des secrets utilisateur.

var configuration = builder.Services.BuildServiceProvider().GetService<IConfiguration>();

Par défaut, les fichiers de configuration tels que appsettings.json ne sont pas automatiquement copiés dans le dossier de sortie Azure Function. Assurez-vous de consulter la documentation ( https://docs.microsoft.com/en-us/azure/azure-functions/functions-dotnet-dependency-injection#customizing-configuration-sources ) pour les modifications apportées à votre fichier .csproj . Notez également qu'en raison de la façon dont la méthode ajoute les fournisseurs existants, il est nécessaire de toujours terminer par .AddEnvironmentVariables () .


0 commentaires