How do I replace a value in "appsettings.json" with a value that I pass in via a docker environment variable

I have an MVC C# app that has a appsettings.json file that looks like this:

{
    "Logging": {
      "LogLevel": {
        "Default": "Warning"
      }
    },
    "AllowedHosts": "*",
    "ConnectionStrings": {
      "db": "Server=postgresql_MENTIONvlt_bg;Database=amaranth_vaultvid_tests;User Id=amaranth_vaultvid_test_user;Password=<PASSWORD HERE>"
    },
    "Kestrel": {
      "Endpoints": {
        "Http": {
          "Url":  "http://0.0.0.0:5000"
        },
        "Https": {
          "Url": "https://0.0.0.0:5001"
        }
      },
      "EndpointDefaults": {
        "Url": "https://0.0.0.0:5001",
        "Protocols": "Http1"
      }
    },
    "ApiEndpoints": {
      "TestNet": [
        "<LINK HERE>",
        "<LINK HERE>",
        "<API KEY HERE>"
      ],
      "MainNet": [
        "<LINK HERE>",
        "<LINK HERE>",
        "<API KEY HERE>"
      ]
    }
  }

I want to replace ApiEndpoints.MainNet[2] with a value that I pass in with docker. My docker-compose.yml file looks like this:

version: '3.8'

volumes:
  data:

services:
  postgresql_MENTIONvlt_bg:
    image: postgres
    # explicit container name
    container_name: postgresql_vlt_bg
    environment:
      - POSTGRES_USER=${POSTGRES_USER}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
      - POSTGRES_DB=${POSTGRES_DB}
    ports:
      - 5432:5432
    volumes:
      - data:/var/lib/postgresql_vlt_bg
  amaranth_main:
    container_name: amaranth_main
    links:
      - postgresql_MENTIONvlt_bg
    depends_on:
      - postgresql_MENTIONvlt_bg
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - 8000:5000
      - 8001:5001
    environment:
      - ASPNETCORE_ENVIRONMENT=Release
      - ASPNETCORE_Kestrel__Certificates__Default__Password=${Kestrel_Cert_Password}
      - ASPNETCORE_Kestrel__Certificates__Default__Path=${Kestrel_Cert_Rel_Path}
      - ApiEndpoints__MainNet=${<NEW API KEY HERE>}
    volumes:
      - ${Kestrel_Cert_Abs_Path}:/https:ro

All of the variables represented with ${...} are defined in an .env file.

When I try to print out ApiEndpoints.MainNet I get the old API key. How do I pass in the new API key?

This is the projects’s Startup.cs file:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using amaranth.Data;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Identity.UI.Services;
using amaranth.Helpers;

namespace amaranth
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddHttpClient();

            services.Configure<ApiEndpoints>(Configuration.GetSection("ApiEndpoints"));

            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => false;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });

            services.AddDbContext<ApplicationDbContext>(options =>
                options.UseNpgsql(Configuration.GetConnectionString("db")));

            services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
                .AddRoles<IdentityRole>()
                .AddEntityFrameworkStores<ApplicationDbContext>();

            services.AddAuthorization();

            services.AddControllersWithViews();
            services.AddRazorPages();

            services.AddSingleton<BitcoinHelper>();

            services.AddTransient<IEmailSender, EmailSender>();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseForwardedHeaders(new ForwardedHeadersOptions
            {
                ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
            });
            
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseCookiePolicy();
            app.UseStaticFiles();
            app.UseRouting();
            app.UseAuthentication();
            app.UseAuthorization();
            app.UseStatusCodePages();

            app.UseEndpoints(endpoints => {
                endpoints.MapControllers();
                endpoints.MapRazorPages();
                endpoints.MapDefaultControllerRoute();
            });
        }
    }
}

And this is the project’s Program.cs file:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using amaranth.Data;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace amaranth
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var host = CreateHostBuilder(args).Build();
            using (var scope = host.Services.CreateScope())
            {
                var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
                db.Database.Migrate();
            }
            host.Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.ConfigureKestrel(serverOptions =>
                    {
                        // Set properties and call methods on options
                    })
                    .UseStartup<Startup>();
                });
    }
}

And the Dockerfile referenced in docker-compose.yml:

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build-env
WORKDIR /app

# Copy everything
COPY . ./
# Restore as distinct layers
RUN dotnet restore
RUN dotnet publish -c Release -o out

# Build runtime image
FROM mcr.microsoft.com/dotnet/aspnet:6.0
WORKDIR /app
COPY --from=build-env /app/out .
ENTRYPOINT ["dotnet", "amaranth.dll"]

So again, just to reiterate, how do I pass in the new API key?

>Solution :

Use ApiEndpoints__MainNet__2

Maybe this document can help you: Naming of environment variables

Leave a Reply