如何解决 docker-compose 环境变量不起作用 ASP.Net Core MVC

Posted

技术标签:

【中文标题】如何解决 docker-compose 环境变量不起作用 ASP.Net Core MVC【英文标题】:How to solve docker-compose environment variables not working ASP.Net Core MVC 【发布时间】:2021-06-12 01:25:24 【问题描述】:

我在 docker-compose 文件中的配置变量无法在 Startup.cs 中读取。我正在使用 Asp.net Core 3.1 和 SQL Server。

这是我的错误信息

blog-app_1      | warn: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[60]
blog-app_1      |       Storing keys in a directory '/root/.aspnet/DataProtection-Keys' that may not be persisted outside of the container. Protected data will be unavailable when container is destroyed.
blog-app_1      | warn: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[35]
blog-app_1      |       No XML encryptor configured. Key 58394e97-3215-43de-abbc-ae7ab801d661 may be persisted to storage in unencrypted form.
blog-app_1      | crit: Microsoft.AspNetCore.Hosting.Diagnostics[6]
blog-app_1      |       Application startup exception
blog-app_1      | System.ArgumentNullException: Value cannot be null. (Parameter 'connectionString')
blog-app_1      |    at Microsoft.EntityFrameworkCore.Utilities.Check.NotEmpty(String value, String parameterName)
blog-app_1      |    at Microsoft.EntityFrameworkCore.SqlServerDbContextOptionsExtensions.UseSqlServer(DbContextOptionsBuilder optionsBuilder, String connectionString, Action`1 sqlServerOptionsAction)
blog-app_1      |    at BlogApplication.Startup.<>c__DisplayClass4_0.<ConfigureServices>b__1(DbContextOptionsBuilder options) in /src/BlogApplication/Startup.cs:line 56
blog-app_1      |    at Microsoft.Extensions.DependencyInjection.EntityFrameworkServiceCollectionExtensions.<>c__DisplayClass1_0`2.<AddDbContext>b__0(IServiceProvider p, DbContextOptionsBuilder b)
blog-app_1      |    at Microsoft.Extensions.DependencyInjection.EntityFrameworkServiceCollectionExtensions.CreateDbContextOptions[TContext](IServiceProvider applicationServiceProvider, Action`2 optionsAction)

这是我的 Startup.cs

我使用Configuration["..."] 来初始化环境变量。 您可以在 public void ConfigureServices(IServiceCollection services) 中看到它。

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

        services.AddControllersWithViews().AddJsonOptions(option =>
        
            option.JsonSerializerOptions.PropertyNamingPolicy = null;
            option.JsonSerializerOptions.DictionaryKeyPolicy = null;
        );

        //Config Database Identity
        var server_identity = Configuration["DBServer"] ?? "mssql-server";
        var port_identity = Configuration["DBPort"] ?? "1433";
        var user_identity = Configuration["DBUsername"] ?? "sa";
        var password_identity = Configuration["DBPass"] ?? "Loc@04071999";
        var dbName_identity = Configuration["DBNameIdentity"] ?? "Identity_BlogApplication";

        //Config Database Blog
        var dbName_blog = Configuration["DBNameBlog"] ?? "Data_BlogApplication";

        string DefaultConnection = $"Server=server_identity, port_identity; Database=dbName_identity; User ID=user_identity; Password=password_identity";
        string DataConnection = $"Server=server_identity, port_identity; Database=dbName_blog; User ID=user_identity; Password=password_identity";

        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(
                Configuration.GetConnectionString(DefaultConnection)));
        services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
            .AddEntityFrameworkStores<ApplicationDbContext>();

        services.AddDbContext<BlogApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString(DataConnection)));

        services.AddTransient<ICommentService, CommentService>();
        services.AddTransient<IBlogService, BlogService>();

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

        //services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
    

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    
        if (env.IsDevelopment())
        
            app.UseDeveloperExceptionPage();
            app.UseDatabaseErrorPage();
        
        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.UseStaticFiles();

        app.UseRouting();

        app.UseAuthentication();
        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "controller=Blog/action=Index/id?");
            endpoints.MapRazorPages();
        );

        
        app.ApplicationServices.CreateScope().ServiceProvider.GetService<ApplicationDbContext>().Database.Migrate();
        app.ApplicationServices.CreateScope().ServiceProvider.GetService<BlogApplicationDbContext>().Database.Migrate();
    c

这是我的 docker-compose.xml

在 docker-compose 中,我为 blog-app 设置了“环境:”

version: '3'
services:
  mssql-server:
    image: "microsoft/mssql-server-linux"
    environment:
      ACCEPT_EULA: "Y"
      SA_PASSWORD: "Loc@04071999"
      MSSQL_PID: Express
    ports:
      - "1433:1433"
  blog-app:
    build: .
    environment:
      DBServer: "mssql-server"
      DBPort: "1433"
      DBUsername: "sa"
      DBPass: "Loc@04071999"
      DBNameIdentity: "Identity_BlogApplication"
      DBNameBlog: "Data_BlogApplication"
    ports: 
      - "3000:80"

感谢您看到我的问题

【问题讨论】:

【参考方案1】:

您使用的方法Configuration.GetConnectionString() 从配置中获取具有提供名称的连接字符串。在您的情况下,名称是变量DefaultConnection 的值。变量应该有值

$"Server=mssql-server, 1433; Database=Identity_BlogApplication; User ID=sa; Password=Loc@04071999"; 

但不存在具有此名称的连接字符串,因此返回null,您将获得ArgumentNullException

您可以通过不调用Configuration.GetConnectionString() 而是将连接字符串直接传递给方法UseSqlServer 来修复它,因为您自己使用环境变量的值构建连接字符串。

所以以下应该可以解决您的问题。

services.AddDbContext<ApplicationDbContext>(options =>  options.UseSqlServer(DefaultConnection));
...
services.AddDbContext<BlogApplicationDbContext>(options => options.UseSqlServer(DataConnection));

但是恕我直言,您不应该自己构建连接字符串,而是使用单个环境变量向您的数据库提供完整的连接字符串。这是使用连接字符串环境变量 (CONNECTIONSTRINGS)

version: '3'
services:
  mssql-server:
    image: "microsoft/mssql-server-linux"
    environment:
      ACCEPT_EULA: "Y"
      SA_PASSWORD: "Loc@04071999"
      MSSQL_PID: Express
    ports:
      - "1433:1433"
  blog-app:
    build: .
    environment:
      CONNECTIONSTRINGS__IDENTITY: "Server=mssql-server, 1433; Database=Identity_BlogApplication; User ID=sa; Password=Loc@04071999"
      CONNECTIONSTRINGS__BLOG: "Server=mssql-server, 1433; Database=Data_BlogApplication; User ID=sa; Password=Loc@04071999"
    ports: 
      - "3000:80"

使用这种方法,您可以在代码中调用Configuration.GetConnectionString(),例如

services.AddDbContext<ApplicationDbContext>(options =>  options.UseSqlServer(Configuration.GetConnectionString("IDENTITY")));
...
services.AddDbContext<BlogApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("BLOG")));

【讨论】:

感谢您的帮助。我按照你的修复,但我有一个新问题 这是我的新问题:blog-app_1 |暴击:Microsoft.AspNetCore.Hosting.Diagnostics[6] blog-app_1 |应用程序启动异常 blog-app_1 | Microsoft.Data.SqlClient.SqlException (0x80131904):建立与 SQL Server 的连接时发生与网络相关或特定于实例的错误。服务器未找到或无法访问。验证实例名称是否正确以及 SQL Server 是否配置为允许远程连接。 (提供者:TCP 提供者,错误:40 - 无法打开与 SQL Server 的连接) 我已经解决了我的问题。在 docker-compose 文件中更改这一行: image: "microsoft/mssql-server-linux --change-> image: "mcr.microsoft.com/mssql/server:2019-latest" 非常感谢。关闭我的话题!

以上是关于如何解决 docker-compose 环境变量不起作用 ASP.Net Core MVC的主要内容,如果未能解决你的问题,请参考以下文章

如何使用来自其他目录的 docker-compose 环境变量

docker-compose环境会覆盖jar中的变量,docker环境变量和jar中的变量是如何映射的?

如何将环境变量从 docker-compose 传递给项目?

如何从.env文件获取环境变量到docker-compose.yml?

如何获得正确的 docker-compose Multiline 环境变量格式?

使用 nginx 将环境变量从 docker-compose 传递到 vue 应用程序