代码之家  ›  专栏  ›  技术社区  ›  nop

如何在本地环境中加载secrets.json而不是在ASP。NET核心?

  •  1
  • nop  · 技术社区  · 5 月前

    我们正在使用 Azure应用程序配置 Azure密钥库 从加载配置。过去有四种环境: Development , QA , Staging , Production ,但现在我们也有 Local 环境。以前,我们使用 发展 为了地方发展,但现在 本地 是当地的。

    问题是 secrets.json 未加载 本地 环境。它只加载 发展 .

    本地环境配置源:

    builder.Sources = ConfigurationManager.ConfigurationSources
      [0] = MemoryConfigurationSource
      [1] = EnvironmentVariablesConfigurationSource
      [2] = EnvironmentVariablesConfigurationSource
      [3] = JsonConfigurationSource ("appsettings.json")
      [4] = JsonConfigurationSource ("appsettings.Local.json")
      [5] = EnvironmentVariablesConfigurationSource
      [6] = ChainedConfigurationSource
    

    开发环境配置源:

    builder.Sources = ConfigurationManager.ConfigurationSources
      [0] = MemoryConfigurationSource
      [1] = EnvironmentVariablesConfigurationSource
      [2] = EnvironmentVariablesConfigurationSource
      [3] = JsonConfigurationSource ("appsettings.json") 
      [4] = JsonConfigurationSource ("appsettings.Development.json")
      [5] = JsonConfigurationSource ("secrets.json")  
      [6] = EnvironmentVariablesConfigurationSource
      [7] = ChainedConfigurationSource
    

    我做了一些研究,并基于 https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-8.0#default-application-configuration-sources :

    应用程序在开发环境中运行时的用户机密

    我相信 secrets.json 仅适用于 发展 默认情况下。那么,我该如何将其转化为行为 本地 环境?

    using Azure.Core;
    using Microsoft.Extensions.Configuration.EnvironmentVariables;
    using Microsoft.Extensions.Configuration.Json;
    using RJO.BuildingBlocks.Common;
    using RJO.BuildingBlocks.Common.Azure;
    using RJO.BuildingBlocks.Common.Azure.AppConfiguration;
    using System.Text.Json;
    
    // ReSharper disable once CheckNamespace
    namespace Microsoft.Extensions.Configuration;
    
    public static class ConfigurationBuilderExtensions
    {
        static readonly TimeSpan LocalCacheDuration = 24.Hours();
    
        public static IConfigurationBuilder AddAzureAppConfiguration(this IConfigurationBuilder builder, StartupLogger logger, string endpoint)
        {
            var azureAppConfigurationSource = new ChainedConfigurationSource
            {
                Configuration = builder.GetAzureAppConfiguration(logger, endpoint)
            };
    
            var nextSource = builder.Sources.FirstOrDefault(x => x is JsonConfigurationSource or EnvironmentVariablesConfigurationSource);
            if (nextSource != null)
            {
                // We insert the Azure source before the JSON and Environment sources so that those take precedence
                var indexOfNextSource = builder.Sources.IndexOf(nextSource);
                builder.Sources.Insert(indexOfNextSource, azureAppConfigurationSource);
            }
            else
                builder.Sources.Add(azureAppConfigurationSource);
    
            return builder;
        }
    
        static IConfiguration GetAzureAppConfiguration(this IConfigurationBuilder builder, StartupLogger logger, string endpoint)
        {
            const string secretsJsonFilename = "secrets.json";
    
            if (builder.Sources.FirstOrDefault(x => x is JsonConfigurationSource { Path: secretsJsonFilename }) is not JsonConfigurationSource secretsSource)
                return GetAzureAppConfiguration(logger, endpoint);
    
            // Check that there are actually some secrets stored (to ensure that caching only works on developer machines)
            var secrets = new ConfigurationBuilder().SetFileProvider(builder.GetFileProvider()).Add(secretsSource).Build().AsEnumerable();
            if (!secrets.Any())
                return GetAzureAppConfiguration(logger, endpoint);
    
            var fileInfo = secretsSource.FileProvider.GetFileInfo(secretsJsonFilename);
            var directory = Path.GetDirectoryName(fileInfo.PhysicalPath);
            var cacheFilename = Path.Join(directory, endpoint.Replace("https://", string.Empty) + ".cached.json");
            if (File.Exists(cacheFilename) && File.GetLastWriteTimeUtc(cacheFilename) > DateTime.UtcNow.Subtract(LocalCacheDuration))
            {
                var expiresIn = DateTime.UtcNow.Subtract(File.GetLastWriteTimeUtc(cacheFilename).Add(LocalCacheDuration)).Duration();
                logger.Info($"Using cached Azure App Configuration from {cacheFilename} (expires in {expiresIn.AsDuration()}) ...");
                return new ConfigurationBuilder().AddJsonFile(cacheFilename).Build();
            }
    
            logger.Info("Cached Azure App Configuration was not found or is expired ...");
            var configuration = GetAzureAppConfiguration(logger, endpoint);
            logger.Info($"Caching Azure App Configuration as {cacheFilename} (expires in {LocalCacheDuration.AsDuration()}) ...");
            var json = JsonSerializer.Serialize(new Dictionary<string, string>(configuration.AsEnumerable()));
            File.WriteAllText(cacheFilename, json);
            return configuration;
        }
    
        static IConfiguration GetAzureAppConfiguration(StartupLogger logger, string endpoint)
        {
            logger.Info("Authenticating with Azure App Configuration ...");
    
            var credential = AzureIdentity.HrvystCredential;
            var configuration = new ConfigurationBuilder()
                .AddAzureAppConfiguration(options => options
                    .ConfigureClientOptions(x => x.AddPolicy(new LoggingPolicy(logger), HttpPipelinePosition.PerRetry))
                    .Connect(new Uri(endpoint), credential)
                    .ConfigureKeyVault(x => x.SetCredential(credential)))
                .Build();
    
            logger.Info("Finished loading Azure App Configuration.");
            return configuration;
        }
    }
    
    1 回复  |  直到 5 月前
        1
  •  1
  •   Guru Stron    5 月前

    您可以手动添加源。例如,对于最小托管模型,它可以如下所示:

    if (builder.Environment.EnvironmentName.Equals("Local", StringComparison.OrdinalIgnoreCase))
    {
        builder.Configuration.AddUserSecrets(typeof(Program).Assembly);
    }
    

    请注意,这将在管道末尾添加机密,如果需要其他顺序,则可以在调用后重新组装整个配置管道 builder.Configuration.Sources.Clear(); 或通过以下方式操纵它 Remove / RemoveAt 和/或 Insert(someIndex, ...); 电话(在 Sources ).

    附笔。

    请注意 builder.Configuration 是a Microsoft.Extensions.Configuration.ConfigurationManager 所以它也是一个建设者 IConfigurationBuilder builderConfiguration = builder.Configuration; .