title: Custom Provider for AWS SSM using Microsoft.Configuration.ConfigurationBuilders
body: <p>I seem to be stuck at developing a custom Key/Value pair provider for Amazon's System Manager Parameter Store (SSM) using NETFramework 4.7.1 that utilizes Microsoft.Configuration.ConfigurationBuilders. </p>
  
  <p>The implementation:</p>
  
  <pre><code>using System;
  using System.Collections.Generic;
  using Amazon.SimpleSystemsManagement;
  using Amazon.SimpleSystemsManagement.Model;
  using Microsoft.Configuration.ConfigurationBuilders;
  using System.Linq;
  using System.Diagnostics;
  using System.Collections.Specialized;
  using Amazon.Runtime;
  using Amazon.Runtime.CredentialManagement;
  using System.Configuration;
  using System.Threading.Tasks;
  
  namespace AXS.Configurations
  {
      public class ParameterStoreConfigBuilder : KeyValueConfigBuilder
      {
          public const string envTag = "Environment";
          public const string appNameTag = "AppName";
  
          private IAmazonSimpleSystemsManagement client;
          /// &lt;summary&gt;
          /// Gets or sets an environment (dev|qa|staging|production)
          /// &lt;/summary&gt;
          public string Environment { get; set; }
          /// &lt;summary&gt;
          /// Gets or sets a AppName 
          /// &lt;/summary&gt;
          public string AppName { get; set; }
  
          public ParameterStoreConfigBuilder(IAmazonSimpleSystemsManagement client,
              string appName,
              string environment)
          {
              this.client = client;
              Environment = environment.ToLower();
              AppName = appName;
          }
          public ParameterStoreConfigBuilder()
          {
              client = new AmazonSimpleSystemsManagementClient();
          }
  
          public override string Description =&gt; "Parameter Store";
          public override string Name =&gt; "SSM";
  
          protected override void LazyInitialize(string name, NameValueCollection config)
          {
              Optional = false;
              base.LazyInitialize(name, config);
              string env = UpdateConfigSettingWithAppSettings(envTag);
              if (string.IsNullOrWhiteSpace(env))
                  throw new ArgumentException($"environment must be specified with the '{envTag}' attribute.");
              Environment = env;
              string appName = UpdateConfigSettingWithAppSettings(appNameTag);
              if (string.IsNullOrWhiteSpace(appName))
                  throw new ArgumentException($"appName must be specified with the '{appNameTag}' attribute.");
              AppName = appName;
              client = new AmazonSimpleSystemsManagementClient("","", Amazon.RegionEndpoint.USWest2);
  
          }
          public override ICollection&lt;KeyValuePair&lt;string, string&gt;&gt; GetAllValues(string prefix)
          {
              Trace.TraceInformation($"return values prefix {prefix}");
              if (client == null)
                  return null;
              var parameters = new List&lt;Parameter&gt;();
              string nextToken = null;
              do
              {
                  var response = client.GetParametersByPath(new GetParametersByPathRequest { Path = prefix, Recursive = true, WithDecryption = true, NextToken = nextToken });
                  nextToken = response.NextToken;
                  parameters.AddRange(response.Parameters);
              } while (!string.IsNullOrEmpty(nextToken));
              return parameters.Select(p =&gt; new
              {
                  Key = p.Name,
                  p.Value
              }).ToDictionary(parameter =&gt; parameter.Key, parameter =&gt; parameter.Value, StringComparer.OrdinalIgnoreCase);
          }
  
          public override string GetValue(string key)
          {
              return Task.Run(async () =&gt; { return await GetValueAsync(key); }).Result;
          }
          private async Task&lt;string&gt; GetValueAsync(string key)
          {
              var name = $"/{Environment}/{AppName}/{key.Replace(':', '/')}";
              Trace.WriteLine($"get value async:{name}");
              if (client == null)
                  return null;
  
              try
              {
                  Trace.TraceInformation($"fetch key {name}");
                  var request = new GetParameterRequest
                  {
                      Name = name,
                      WithDecryption = true
                  };
                  var response = await client.GetParameterAsync(request);
                  var parameter = response.Parameter;
                  var value = parameter.Type == ParameterType.SecureString ? "*****" : parameter.Value;
                  Trace.TraceInformation($"fetched name={name} value={value}");
                  return value;
              }
              catch (Exception e) when (Optional &amp;&amp; ((e.InnerException is System.Net.Http.HttpRequestException) || (e.InnerException is UnauthorizedAccessException))) { }
  
              return null;
          }
      }
  }
  </code></pre>
  
  <p>The problem seems to be that AWS SSM <code>client</code> never gets created.
  If I change the code and try to instantiate in the constructor I get a stack overflow exception due to recursion.</p>
  
  <p>Any ideas on how to force to get AmazonSimpleSystemsManagementClient created?</p>
  
  <p>The code uses guidance from <a href="https://github.com/aspnet/MicrosoftConfigurationBuilders" rel="nofollow noreferrer">https://github.com/aspnet/MicrosoftConfigurationBuilders</a></p>
  
  <p>The App.Config</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt;
  &lt;configuration&gt;
    &lt;configSections&gt;
      &lt;section name="configBuilders" type="System.Configuration.ConfigurationBuildersSection, 
               System.Configuration, Version=4.0.0.0, Culture=neutral, 
               PublicKeyToken=b03f5f7f11d50a3a" 
               restartOnExternalChanges="false" 
               requirePermission="true" /&gt;
    &lt;/configSections&gt;
    &lt;configBuilders&gt;
      &lt;builders&gt;
        &lt;add name="ParameterStore" Environment="development" AppName="myAppNameforParmStore" type="AXS.Configurations.ParameterStoreConfigBuilder, AXS.Configurations" /&gt;
        &lt;add name="Env" prefix="appsettings_" stripPrefix="true" type="Microsoft.Configuration.ConfigurationBuilders.EnvironmentConfigBuilder, Microsoft.Configuration.ConfigurationBuilders.Environment, Version=2.0.0.0, Culture=neutral" /&gt;
      &lt;/builders&gt;
    &lt;/configBuilders&gt;
    &lt;startup&gt;
      &lt;supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.1" /&gt;
    &lt;/startup&gt;
    &lt;appSettings configBuilders="Env,ParameterStore"&gt;
      &lt;add key="Url" value="URL Value for from paramter Store" /&gt;
      &lt;add key="Secret" value="Some Secret value decrypted" /&gt;
    &lt;/appSettings&gt;
  &lt;/configuration&gt;
  </code></pre>
  
  <p>Thanks</p>