Nous devons ajouter des fournisseurs de configuration à l'IConfiguration native fournie aux fonctions Azure de manière native. À l' heure actuelle , nous sommes complètement remplaçons avec notre IConfiguration de mesure utilisant le code suivant:
public class Startup : FunctionsStartup { public override void Configure(IFunctionsHostBuilder builder) { ... var configuration = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddAzureKeyVault(...) .AddJsonFile("local.settings.json", true, true) .AddEnvironmentVariables() .Build(); builder.Services.AddSingleton<IConfiguration>(configuration); builder.Services.AddSingleton<IMyService, MyService>(); } }
Un certain contexte
MyService a besoin dans son constructeur des valeurs du fournisseur KeyVault et également d'autres instances comme Application Insights, etc. Si nous laissons l'IConfiguration par défaut, il n'a pas les valeurs KeyVault. Si nous créons l'instance MyService avec une fabrique, nous devons fournir manuellement l'instance App Insights, etc. Remplacement actuel des compilations IConfiguration et exécution de la fonction. Mais cela rompt un autre comportement par défaut comme ne pas prendre les configurations de host.json (nous essayons de configurer le déclencheur de file d'attente). L'utilisation de IConfiguration par défaut lit correctement les paramètres de host.json.
3 Réponses :
{ "DbConfig": { "SuperSecretValue": "abc123" } }
IOptions<T>
Au lieu de remplacer l'instance injectée d'IConfiguration ou d'utiliser l'option 1 ci-dessus, rendez vos services en aval dépendants d'un IOptions<T>
. Je pense que c'est le meilleur modèle, car vous pouvez diviser votre configuration en petits segments en fonction de vos besoins et faire en sorte que vos services prennent des dépendances plus ciblées.
public class MyService : IMyService { private MyDbConfig _dbConfig; public MyService(IOptions<MyDbConfig> myDbConfig) { _dbConfig = myDbConfig.Value; } }
Dans ce scénario, MyDbConfig
est juste un POCO avec des propriétés pour héberger votre configuration. Votre classe de service prend la dépendance sur IOptions<MyDbConfig>
:
var configuration = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddAzureKeyVault(...) .AddJsonFile("local.settings.json", true, true) .AddEnvironmentVariables() .Build(); // don't re-bind IConfiguration // builder.Services.AddSingleton<IConfiguration>(configuration); // instead, bind sections specific to what services may need builder.Services.Configure<MyDbConfig>(config.GetSection("DbConfig"));
Dans les configurations basées sur JSON, vous incluez "DbConfig" (ou tout autre argument que vous fournissez à GetSection
) en tant qu'objet JSON de niveau supérieur, avec vos valeurs de configuration en tant que propriétés dans cet objet:
// ... var baseConfig = builder.Services.BuildServiceProvider().GetService<IConfiguration>(); var configuration = new ConfigurationBuilder() .AddConfiguration(baseConfig) .SetBasePath(Directory.GetCurrentDirectory()) .AddAzureKeyVault(...) .AddJsonFile("local.settings.json", true, true) .AddEnvironmentVariables() .Build(); // ...
Dans KeyVault, vous utilisez --
pour indiquer le modèle d'imbrication, avec un nom secret tel que DbConfig--SuperSecretValue
.
Il y a quelques commentaires sur l'utilisation des fonctions Azure .NET Core:
IConfiguration
. Comme @Dusty l'a mentionné, la méthode IOptions
consiste à utiliser le modèle IOptions
.AddAzureKeyVault()
car vous pouvez et devez le configurer dans le portail azure à l'aide des références Azure Key Vault. Documents sur Key Vault . En faisant cela, le mécanisme de configuration de la fonction azure ne sait pas / ne se soucie pas où il s'exécute, si vous l'exécutez localement, il se chargera à partir de local.settings.json, s'il est déployé, il obtiendra les valeurs de la configuration de l'application Azure et si vous avez besoin de l'intégration d'Azure Key Vault, tout est effectué via les références Azure Key Vault. Cela étant dit, vous pouvez toujours accomplir ce que vous voulez même si ce n'est pas recommandé en procédant comme suit. Gardez à l'esprit que vous pouvez également ajouter les références de coffre-fort de clés dans le code suivant par AddAzureKeyVault()
var configurationBuilder = new ConfigurationBuilder(); var descriptor = builder.Services.FirstOrDefault(d => d.ServiceType == typeof(IConfiguration)); if (descriptor?.ImplementationInstance is IConfiguration configRoot) { configurationBuilder.AddConfiguration(configRoot); } // Conventions are different between Azure and Local Development and API // https://github.com/Azure/Azure-Functions/issues/717 // Environment.CurrentDirectory doesn't cut it in the cloud. // https://stackoverflow.com/questions/55616798/executioncontext-in-azure-function-iwebjobsstartup-implementation var localRoot = Environment.GetEnvironmentVariable("AzureWebJobsScriptRoot"); var actualRoot = $"{Environment.GetEnvironmentVariable("HOME")}/site/wwwroot"; var basePath = localRoot ?? actualRoot; var configuration = configurationBuilder .SetBasePath(basePath) .AddJsonFile("local.settings.json", optional: true, reloadOnChange: false) .AddEnvironmentVariables() .Build(); builder.Services.Replace(ServiceDescriptor.Singleton(typeof(IConfiguration), configuration));
Faites-moi savoir si vous avez besoin de plus de commentaires / clarifications à ce sujet et je mettrai à jour ma réponse en conséquence.
Excellente réponse. Bien expliqué, fournit toutes les options, des liens vers la documentation et donne même un exemple de code. Voudrais entendre OP et confirmer que cela fonctionne.
@TroyWitthoeft Merci! Je peux confirmer que cela fonctionne bien. Il y a quelques semaines, il y a quelques semaines dans le trou du lapin de configuration Azure Functions :)
Une solution plus simple consisterait à 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.
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(); }
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 () .
Une discussion plus approfondie sur la configuration dans une fonction Azure est disponible sur Utilisation de ConfigurationBuilder dans FunctionsStartup
La question ici n'est pas du tout claire.
@Tom Au lieu de remplacer, nous devons modifier l'IConfiguration par défaut.
docs.microsoft.com/en-us/azure/azure-app-configuration/...
@ user33276346 Jetez un œil à ce stackoverflow.com/a/60078802/5233410
@Aluan 438 $ par an, n'y a-t-il pas une solution de contournement de codage?
@Nkosi J'ai essayé votre solution, mais comme le mentionne Anthony Brenelière, elle remplace quelque chose dans le runtime de la fonction. Le problème est que la solution Anthony Brenelière ne s'adapte pas à nos besoins car nous devons passer la configuration d'origine ainsi que notre configuration particulière (fichiers, KeyVault, etc.) sans modifier le comportement normal de Function. Par exemple, nous devons modifier le nombre de tentatives pour un déclencheur de file d'attente en le définissant dans host.json. Si nous laissons la configuration injectée par défaut, cela fonctionne. Mais si nous appliquons votre solution ou la nôtre, elle ignore les paramètres de nouvelle tentative et suit le comportement par défaut.
@Nkosi la configuration host.json dont je parle: "extensions": {"queues": {"maxDequeueCount": 3, "visibilitéTimeout": "00:00:30"}} Tiré de docs.microsoft.com/ fr-fr / azure / azure-functions /…