0

In local I need to connect to database using appsettings.json but in other environments like dev,staging and prod need to get connection string for db from azure key vault.In launchsettings.json I have set environment to local and when I run the project in local I am getting error in program.cs as 'The ConfigureServices method must either be parameterless or take only one parameter of type IServiceCollection.'Please let me know what is the issue here or how to fix it

appsettings.json

{
  "KeyVault": {
    "Vault": "Bookskv"
  },
  "MongoConnection": {
  "ConnectionString": "<set by keyvault>",
    "Database": "Books"
  },
  "MongoLocal": {
    "ConnectionString": "mongodb:localhost:1230",
    "Database": "Books"
  }
}

Program.cs

  public static IWebHost CreateWebHostBuilder(string[] args)
        {
            return WebHost.CreateDefaultBuilder(args)
               .ConfigureAppConfiguration((ctx, builder) =>
                 {
                     var keyName = string.Empty;
                     if (ctx.HostingEnvironment.EnvironmentName!="Local")
                     {
                         var keyVaultEndpoint = GetKeyVaultEndpoint();
                         if (!string.IsNullOrEmpty(keyVaultEndpoint))
                         {
                             var azureServiceTokenProvider = new AzureServiceTokenProvider();
                             var keyVaultClient = new KeyVaultClient(
                                 new KeyVaultClient.AuthenticationCallback(
                                     azureServiceTokenProvider.KeyVaultTokenCallback));
                             if(ctx.HostingEnvironment.EnvironmentName=="Development")
                             {
                                  keyName = "BooksdevDb";
                             }
                             else if(ctx.HostingEnvironment.EnvironmentName == "Production")
                             {
                                  keyName = "BooksprodDb";
                             }
                             var secretBundle =  keyVaultClient.GetSecretAsync("https://Bookskv.vault.azure.net/secrets/{keyName}").Result;
                             var secret = secretBundle.Value;                          
                           
                             builder.AddAzureKeyVault(
                                 keyVaultEndpoint, keyVaultClient, new DefaultKeyVaultSecretManager());
                         }
                   
                     }                    
                 }
              ).UseUrls("http://localhost:44315")
               .UseKestrel()
               .UseIISIntegration()
               .UseIIS()
               .UseStartup<Startup>()
               .Build();
        }
        private static string GetKeyVaultEndpoint() => "https://Bookskv.vault.azure.net";

    }

Startup.cs

  services.Configure<Settings>(options =>
            {

                if (env.IsDevelopment() || env.IsStaging() || env.IsProduction()) 
                {
                    options.ConnectionString = Configuration.GetSection("MongoConnection:ConnectionString").Value;
                    options.Database = Configuration.GetSection("MongoConnection:Database").Value;
                }
                else
                {
                    options.ConnectionString = Configuration.GetSection("MongoLocal:ConnectionString").Value;
                    options.Database = Configuration.GetSection("MongoLocal:Database").Value;
                }
            });

Settings.cs

 public class Settings
    {
        public string ConnectionString;
        public string Database;
    }
  • could you show the definition of your `ConfigureServices` method please ? Also with version are using v4 ? in process or isolated process ? – Thomas Aug 29 '22 at 06:47

1 Answers1

0

I have already implemented same thing in my project. Donot need to write too much code.

Before Implementing/Following below steps. DO THE STEPS WHICH I MENTIONED IN ANSWER OF THIS QUESTION

  1. Create Two AppSettings :- appsettings.Development.json and appsettings.Production.json

appsettings.Development.json

{
   "DBConnection": "xyz"
}

appsettings.Production.json

{
   "KeyVaultName": "keyvalutname"
}
  1. Add/Install Nuget Package for KeyVault

Azure.Security.KeyVault.Secrets

  1. Create KeyVaultManagement class
public class KeyVaultManagement
   {
      private readonly IConfiguration _config;

      public KeyVaultManagement(IConfiguration config)
      {
        _config= config;
      }

      public SecretClient SecretClient
      {
        get
         {
            return new SecretClient(
                             new Uri($"https://{this._config["KeyVaultName"]}.vault.azure.net/"),
                             new DefaultAzureCredential()) ;
         }
       }
  }
  1. Write the below code in Program.cs
.ConfigureAppConfiguration((context, config) =>
{
   var builtConfig = config.Build();
   if (!context.HostingEnvironment.IsDevelopment())
   {
     config.AddAzureKeyVault(new KeyVaultManagement(builtConfig).SecretClient, new KeyVaultSecretManager());
   }
});
  1. Write the below where need to fetch secret.
var valueofSecret = configuration["DBConnection"];

configuration is IConfiguration

IF YOUR APPLICATION IS NOT APP SERVICE OR IT IS DEVELOPED IN .NET FRAMEWORK

Then Implement KEYVAULT using Certificate

  1. Install Same Nuget Packages

  2. Write the below code in Program.cs. Might need to add package or namespace to use certificate classes

.ConfigureAppConfiguration((context, config) =>
{
   var root = config.Build();
   var KeyVaultName = root["KeyVaultName"];
   var Uri = new Uri($"https://{KeyVaultName}.vault.azure.net/");
   var x509Certifcate = CertifcateHelper.GetCertificate(root["Thumprint"],"KeyVaultCertificate");
   
     config.AddAzureKeyVault(Uri , new ClientCertificateCredential(root["ClientTenantId"], root["ClientAppId"], x509Certifcate));
});

  1. Add the below lines in APPSetting

appsettings.Development.json

{
   "KeyVaultName": "keyvalutname",
   "ClientTenantId": "Get from azure and paste here",
   "ClientAppId": "Get from azure and paste here",
   "Thumbprint": "Get from keyvalut certificate in azure and paste here";
}
  1. Write the below where need to fetch secret.
var valueofSecret = configuration["DBConnection"];
Pradeep Kumar
  • 1,193
  • 1
  • 9
  • 21
  • var valueofSecret = configuration["DBConnection"]; I got this in controller but not in a class. How I can get it in repository class. I get error when I type var valueofSecret = configuration["DBConnection"];. If I add the IConfigurtion in constructor then I am not sure what to enter as a parameter in a class which uses it. Can yo help – Jashvita Oct 28 '22 at 14:53
  • I did exactly what you are trying to do. You have to pass IConfigurtion in constructor. same in class which use it. Can you share your code. – Pradeep Kumar Oct 28 '22 at 17:31
  • let me know if you still facing issue. – Pradeep Kumar Oct 28 '22 at 17:46