簡體   English   中英

如何將 appsettings.json 文件添加到我的 Azure Function 3.0 配置?

[英]How to add an appsettings.json file to my Azure Function 3.0 configuration?

新的 Azure Function 3.0 SDK 提供了一種實現 Startup 類的方法。 它允許訪問依賴注入可用的服務集合,我可以在其中添加自己的組件和第三方服務。

但我不知道如何使用配置文件。

[assembly: FunctionsStartup(typeof(MyNamespace.Startup))]
namespace MyNamespace
{
    public class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder)
        {
...

我的第三方服務以大型結構為參數,這些配置文件與二進制文件一起復制。 我可以將它們復制到appsettings.json文件的一個小節中:

{
  "MachineLearningConfig" : {
     ( about 50+ parameters and subsections )
  }
}

根據部署環境更新配置值。 為此,我使用 Azure Devops 的文件轉換任務:生產值不同於 staging 和 dev 值。

鑒於文檔https://docs.microsoft.com/en-us/azure/azure-functions/functions-dotnet-dependency-injection加載這些選項的方法是:

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

但這需要將所有設置添加為主機環境中的鍵/值字符串,這是我不想做的。 它們太多了,不像在 json 配置文件中那樣容易維護。

我將appsettings.jsonhost.json一起復制。

但是 Azure Function SDK 在啟動時讀取的appsettings.json文件不是我的應用程序的 appsettings.json,而是 Azure Function 工具的 appsettings.json。 因此configuration.GetSection("MachineLearningConfig")返回空值,因為 Azure Function 工具 bin 文件夾中沒有appsettings.json文件。

所以,我的問題是:如何從我的appsetting.json文件中讀取我的MachineLearningConfig部分,作為IOption<MachineLearningConfig>在我的應用程序中注入?

在 Azure Functions v3 中,您可以使用 ASP.NET-Core 中的appsettings.json配置模式和下面的ConfigureAppConfiguration調用( 參考)。

此外,通過使用下面Configure方法中的代碼來更改添加選項的方式。 您不應該將IConfiguration傳遞給IServiceProvider.Configure<>() 這將允許您使用注入的IOptions<MachineLearningConfig>對象。

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

[assembly: FunctionsStartup(typeof(Startup))]

namespace MyAzureFunction
{
    public class Startup : FunctionsStartup
    {
        public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
        {
            if (builder == null) throw new ArgumentNullException(nameof(builder));

            var context = builder.GetContext();

            builder.ConfigurationBuilder
                .AddAppsettingsFile(context)
                .AddAppsettingsFile(context, useEnvironment: true)
                .AddEnvironmentVariables();
        }

        public override void Configure(IFunctionsHostBuilder builder)
        {
            if (builder == null) throw new ArgumentNullException(nameof(builder));

            var configuration = builder.GetContext().Configuration;

            builder.Services.Configure<MachineLearningConfig>(options =>
            {
                configuration.GetSection("MachineLearningConfig").bind(options);
            });
        }
    }

    public static class ConfigurationBuilderExtensions
    {
        public static IConfigurationBuilder AddAppsettingsFile(
            this IConfigurationBuilder configurationBuilder,
            FunctionsHostBuilderContext context,
            bool useEnvironment = false
        )
        {
            if (context == null) throw new ArgumentNullException(nameof(context));

            var environmentSection = string.Empty;

            if (useEnvironment)
            {
                environmentSection = $".{context.EnvironmentName}";
            }

            configurationBuilder.AddJsonFile(
                path: Path.Combine(context.ApplicationRootPath, $"appsettings{environmentSection}.json"),
                optional: true,
                reloadOnChange: false);

            return configurationBuilder;
        }
    }
}

Nkosi 的解決方案運行良好,但它通過替換 IConfiguration 單例: services.AddSingleton<IConfiguration>更新了 azure 函數運行時為自身加載設置的方式。

我更喜歡有另一個未注入的 IConfigurationRoot。 我只需要注入鏈接到我自己的 IConfigurationRoot 的設置IOption<MachineLearningSettings>

我構建了另一個 IConfigurationRoot,它是 Startup 類的成員:

public class Startup : FunctionsStartup
{
    private IConfigurationRoot _functionConfig = null;

    private IConfigurationRoot FunctionConfig( string appDir ) => 
        _functionConfig ??= new ConfigurationBuilder()
            .AddJsonFile(Path.Combine(appDir, "appsettings.json"), optional: true, reloadOnChange: true)
            .Build();

    public override void Configure(IFunctionsHostBuilder builder)
    {
         builder.Services.AddOptions<MachineLearningSettings>()
             .Configure<IOptions<ExecutionContextOptions>>((mlSettings, exeContext) =>
                 FunctionConfig(exeContext.Value.AppDirectory).GetSection("MachineLearningSettings").Bind(mlSettings) );
    }
}

注意:連接字符串必須保留在應用程序設置中,因為觸發器需要它來創建未啟動的函數應用程序的實例(在消費服務計划中)。

有了這個.NET Core 3.1Azure Function 3 花了一個小時天。 這是我想出的。

[assembly: FunctionsStartup(typeof(Ugly.AzureFunctions.Startup))]

namespace Ugly.AzureFunctions
{
    class Startup : FunctionsStartup
    {
        public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
        {
            try
            {
                // On Azure, we need to get where the app is.
                // If you use Directory.GetCurrentDirectory(), you will get something like D:\Program Files (x86)\SiteExtensions\Functions\3.0.14785\32bit
                var basePath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "..");
                var environmentName = builder.GetContext().EnvironmentName;
                builder.ConfigurationBuilder
                    .SetBasePath(basePath)
                    .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                    .AddJsonFile($"appsettings.{environmentName}.json", optional: true, reloadOnChange: true)
                    .AddEnvironmentVariables();
            }
            catch (Exception ex)
            {
                // Handle exceptions about this. Which __should__ never ever happen.
                // The previous comment is sarcastic.
                throw;
            }
        }

        public override void Configure(IFunctionsHostBuilder builder)
        {
            try
            {
                // DO NOT add the configuration as Singleton.
                // If you need the IConfiguration:
                //var configuration = builder.GetContext().Configuration;

                builder.Services
                    .AddOptions<MachineLearningConfig>()
                    .Configure<IConfiguration>((settings, configuration) => {
                        configuration.GetSection("MachineLearningConfig").Bind(settings);
                });
            }
            catch (Exception ex)
            {
                // Handle or not handle? That's the question.
                throw;
            }
        }
    }
}

在啟動類中:

    IConfigurationRoot config = new ConfigurationBuilder()
              .SetBasePath(Environment.CurrentDirectory)
              .AddJsonFile("someSettings.json", optional: true, reloadOnChange: true)
              .AddEnvironmentVariables()
              .Build();

將一個 json 文件添加到您的項目中以保存設置。 請注意,在部署期間會忽略/刪除 local.settings.json。 (將文件命名為其他名稱。)

經過一番研究,我在 Githib 上發現了這個帖子

在函數應用中使用 appsettings.json + IConfiguration

我根據顯示有效的評論和建議制作了以下擴展。

public static class FunctionHostBuilderExtensions {
    /// <summary>
    /// Set up the configuration for the builder itself. This replaces the 
    /// currently registered configuration with additional custom configuration.
    /// This can be called multiple times and the results will be additive.
    /// </summary>
    public static IFunctionsHostBuilder ConfigureHostConfiguration (
        this IFunctionsHostBuilder builder, 
        Action<IServiceProvider, IConfigurationBuilder> configureDelegate) {
        IServiceCollection services = builder.Services;            
        var providers = new List<IConfigurationProvider>();            
        //Cache all current configuration provider
        foreach (var descriptor in services.Where(d => d.ServiceType == typeof(IConfiguration)).ToList()) {
            var existingConfiguration = descriptor.ImplementationInstance as IConfigurationRoot;
            if (existingConfiguration is null) {
                continue;
            }
            providers.AddRange(existingConfiguration.Providers);
            services.Remove(descriptor);
        }
        //add new configuration based on original and newly added configuration
        services.AddSingleton<IConfiguration>(sp => {
            var configurationBuilder = new ConfigurationBuilder();                    
            //call custom configuration
            configureDelegate?.Invoke(sp, configurationBuilder);                
            providers.AddRange(configurationBuilder.Build().Providers);                
            return new ConfigurationRoot(providers);
        });            
        return builder;
    }
}

主要思想是提取所有當前注冊的配置相關類型,創建一個新的構建器,應用自定義配置並構建一個將原始配置和自定義配置細節合並為一個的新配置。

然后它將在Startup

public class Startup : FunctionsStartup {
    public override void Configure(IFunctionsHostBuilder builder) {
        builder.ConfigureHostConfiguration((sp, config) => {
            var executioncontextoptions = sp.GetService<IOptions<ExecutionContextOptions>>().Value;
            var currentDirectory = executioncontextoptions.AppDirectory;

            config
                .SetBasePath(currentDirectory)
                .AddJsonFile("appSettings.json", optional: true, reloadOnChange: true)
                .AddEnvironmentVariables();

            //if there are multiple settings files, consider extracting the list,
            //enumerating it and adding them to the configuration builder.
        });

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

以上現在應該能夠從您的自定義配置中獲取設置。

MS Docs 已更新配置示例

請記住安裝先決條件部分中列出的必需庫。

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

在本地開發函數應用時,必須在local.settings.json項目文件中維護這些值的本地副本。 要了解更多信息,請參閱Local settings文件。

將所需設置上傳到 Azure 中的函數應用的最簡單方法是使用成功發布項目后顯示的管理Application Settings...鏈接。

有關如何獲取這些設置值的信息,請參閱此example

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

這是一個sample project

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM