使用AddAzureKeyVault使我的应用程序慢10秒 [英] Using AddAzureKeyVault makes my application 10 seconds slower

查看:41
本文介绍了使用AddAzureKeyVault使我的应用程序慢10秒的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个非常简单的.NET Core应用程序:

I’m having this very simple .NET Core application:

    static void Main(string[] args)
    {
        var builder = new ConfigurationBuilder()
           .SetBasePath(Directory.GetCurrentDirectory())
           .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);

        builder.AddAzureKeyVault("https://MyKeyVault.vault.azure.net");

        var stopwatch = new Stopwatch();
        stopwatch.Start(); 
        var configuration = builder.Build();
        var elapsed = stopwatch.Elapsed;

        Console.WriteLine($"Elapsed time: {elapsed.TotalSeconds}");
    }

csproj文件如下:

The csproj-file looks like this:

<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
  <OutputType>Exe</OutputType>
  <TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>

<ItemGroup>
  <PackageReference Include="Microsoft.Extensions.Configuration" Version="2.1.1" />
  <PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="2.1.1" />
  <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="2.1.1" />
  <PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="2.1.1" />
  <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.1.1" />
</ItemGroup>

</Project>

我的问题是,在连接了调试器的情况下,该应用程序大约需要10秒钟才能执行(没有调试器的情况下,则大约需要5秒钟).如果我使用 AddAzureKeyVault 删除该行,则该应用程序将在不到一秒钟的时间内执行.我知道 AddAzureKeyVault 将使应用程序连接到Azure并从密钥库中读取值,但是我希望这样做会更快.

My problem is that the application takes about 10 seconds to execute with a debugger attached (about 5 seconds without a debugger). If I remove the line with AddAzureKeyVault the application is executed in less than a second. I know that AddAzureKeyVault will make the application connect to Azure and read values from a key vault but I expected this to be a lot faster.

这是预期的行为吗?我可以做些什么来加快速度吗?

Is this an expected behaviour? Is there anything I could do to make this faster?

推荐答案

先前建议的带有clientId和AzureServiceTokenProvider的解决方案确实对已弃用的数据包产生了影响 Azure.Security.KeyVault.Secrets 这些解决方案在我的测量中不再需要.

The previously suggested solutions with clientId and AzureServiceTokenProvider do have an affect in the deprecated packet Microsoft.Azure.KeyVault. But with the new packet Azure.Security.KeyVault.Secrets these solutions are no longer necessary in my measurements.

我的解决方案是从Azure KeyVault缓存配置并在本地存储该配置.使用此解决方案,您将能够在开发过程中使用Azure KeyVault,并且仍具有出色的性能.以下代码显示了如何执行此操作:

My solution is to cache the configuration from Azure KeyVault and store that configuration locally. With this solution you will be able to use Azure KeyVault during development and still have a great performance. This following code shows how to do this:

using Azure.Extensions.AspNetCore.Configuration.Secrets;
using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text.Json;

namespace ConfigurationCache
{
    public class Program
    {
        private static readonly Stopwatch Stopwatch = new Stopwatch();

        public static void Main(string[] args)
        {
            Stopwatch.Start();
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((ctx, builder) =>
                {
                    builder.AddAzureConfigurationServices();
                })
                .ConfigureServices((hostContext, services) =>
                {
                    Stopwatch.Stop();

                    Console.WriteLine($"Start time: {Stopwatch.Elapsed}");
                    Console.WriteLine($"Config: {hostContext.Configuration.GetSection("ConnectionStrings:MyContext").Value}");

                    services.AddHostedService<Worker>();
                });
    }

    public static class AzureExtensions
    {
        public static IConfigurationBuilder AddAzureConfigurationServices(this IConfigurationBuilder builder)
        {
            // Build current configuration. This is later used to get environment variables.
            IConfiguration config = builder.Build();

#if DEBUG
            if (Debugger.IsAttached)
            {
                // If the debugger is attached, we use cached configuration instead of
                // configurations from Azure.
                AddCachedConfiguration(builder, config);

                return builder;
            }
#endif

            // Add the standard configuration services
            return AddAzureConfigurationServicesInternal(builder, config);
        }

        private static IConfigurationBuilder AddAzureConfigurationServicesInternal(IConfigurationBuilder builder, IConfiguration currentConfig)
        {
            // Get keyvault endpoint. This is normally an environment variable.
            string keyVaultEndpoint = currentConfig["KEYVAULT_ENDPOINT"];

            // Setup keyvault services
            SecretClient secretClient = new SecretClient(new Uri(keyVaultEndpoint), new DefaultAzureCredential());
            builder.AddAzureKeyVault(secretClient, new AzureKeyVaultConfigurationOptions());

            return builder;
        }

        private static void AddCachedConfiguration(IConfigurationBuilder builder, IConfiguration currentConfig)
        {
            //Setup full path to cached configuration file.
            string path = System.IO.Path.Combine(
                Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
                "MyApplication");
            string filename = System.IO.Path.Combine(path, $"configcache.dat");

            // If the file does not exists, or is more than 12 hours, update the cached configuration.
            if (!System.IO.File.Exists(filename) || System.IO.File.GetLastAccessTimeUtc(filename).AddHours(12) < DateTime.UtcNow)
            {
                System.IO.Directory.CreateDirectory(path);

                UpdateCacheConfiguration(filename, currentConfig);
            }

            // Read the file
            string encryptedFile = System.IO.File.ReadAllText(filename);

            // Decrypt the content
            string jsonString = Decrypt(encryptedFile);

            // Create key-value pairs
            var keyVaultPairs = JsonSerializer.Deserialize<Dictionary<string, string>>(jsonString);

            // Use the key-value pairs as configuration
            builder.AddInMemoryCollection(keyVaultPairs);
        }

        private static void UpdateCacheConfiguration(string filename, IConfiguration currentConfig)
        {
            // Create a configuration builder. We will just use this to get the
            // configuration from Azure.
            ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();

            // Add the services we want to use.
            AddAzureConfigurationServicesInternal(configurationBuilder, currentConfig);

            // Build the configuration
            IConfigurationRoot azureConfig = configurationBuilder.Build();

            // Serialize the configuration to a JSON-string.
            string jsonString = JsonSerializer.Serialize(
                azureConfig.AsEnumerable().ToDictionary(a => a.Key, a => a.Value),
                options: new JsonSerializerOptions()
                {
                    WriteIndented = true
                }
                );

            //Encrypt the string
            string encryptedString = Encrypt(jsonString);

            // Save the encrypted string.
            System.IO.File.WriteAllText(filename, encryptedString);
        }

        // Replace the following with your favorite encryption code.

        private static string Encrypt(string str)
        {
            return Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(str));
        }

        private static string Decrypt(string str)
        {
            return System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(str));
        }
    }
}

这篇关于使用AddAzureKeyVault使我的应用程序慢10秒的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆