首页 文章

如何在.Net Core启动中根据环境动态选择连接字符串?

提问于
浏览
0

在StartUp类的ASP.Net MVC Core的Configure方法中,“IHostingEnvironment env”通过Dependency Injection传入 . 并且可以基于环境做出决定 . 例如,

if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseDatabaseErrorPage();
            app.UseBrowserLink();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
        }

在ConfigureServices中,我想做这样的事情来选择正确的连接字符串 . 就像是:

if (env.IsDevelopment())
        {
            services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
        }
        else if (env.IsStaging())
        {
            // Add Staging Connection
        }
        else
        {
            // Add Prod Connection
        }

但默认情况下,“IHostingEnvironment env”不会传递给ConfigureServices方法 . 所以我修改了签名:

public void ConfigureServices(IServiceCollection services)

public void ConfigureServices(IServiceCollection services, IHostingEnvironment env)

并在ConfigureServices中:

if (env.IsDevelopment())
        {
            services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
        }
        else if (env.IsStaging())
        {
            // Add Staging Connection
        }
        else
        {
            // Add Prod Connection
        }

所以现在当我运行时,我收到此错误消息:

“ConfigureServices方法必须是无参数的,或者只接受一个IServiceCollection类型的参数 . ”

ConfigureServices()不会接受IHostingEnvironment var .

但是“Startup.StartUp(IHostingEnvironment env)”确实如此 . 我考虑添加一个StartUp类字段并从Startup()将其设置为正确的环境,然后使用该字段在ConfigureServices中创建决策流 . 但这似乎是一个黑客 .

我知道环境是.Net Core中的一流概念 . 有没有办法直接从appsetting.json做到这一点?

完成此任务的最佳做法是什么?

3 回答

  • 2

    _s82944_就像Sam说的那样,Joe的解决方案,虽然运行正常,但这是一个黑客攻击 . 从ASP.Net Core 1.1开始,对不同环境使用不同连接的正确方法是从appsettings.json文件本身处理它,而不是在ConfigureServices方法中检查环境 . 默认情况下,项目带有 appsettings.jsonappsettings.Development.json 文件(如果需要,可以使用命名约定手动创建另一个用于Staging的文件)

    所以在Joe的解决方案中,您不需要在构造函数中设置环境的值,也不需要使用它来在ConfigurServices中检查它的托管环境 . 所以摆脱:

    environment = env; ........ public IHostingEnvironment environment {get;组; } ........ //另外,在ConfigureServices方法中删除if / else .

    所以你的ConfigureServices方法只会注入:

    services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
    

    现在,您的 appsettings.json 将:

    "ConnectionStrings": {
        "DefaultConnection": "//Value of your connection string for Production Env."
      }
    

    你的 appsettings.Development.json 将有:

    "ConnectionStrings": {
            "DefaultConnection": "//Value of your connection string for Development Env."
          }
    

    现在,如果您查看构造函数方法,var builder 已经加载了两个appsettings文件,并且根据您是在开发环境还是已发布的 生产环境 环境中运行项目,它将使用正确的文件,从而使用其中定义的设置 .

  • 3

    IHostingEnvrionment传递给Startup的构造函数,从那里你可以将它持久保存到属性然后从ConfigureSerivces中使用它

    public Startup(IHostingEnvironment env)
        {
            var builder = new ConfigurationBuilder()
                .SetBasePath(env.ContentRootPath)
                .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
    
            // add this file name to your .gitignore file
            // so you can create it and use on your local dev machine
            // remember last config source added wins if it has the same settings
            builder.AddJsonFile("appsettings.dev.json", optional: true);
            builder.AddEnvironmentVariables();
    
            Configuration = builder.Build();
    
            environment = env;
        }
    
        public IHostingEnvironment environment { get; set; }
    
    public void ConfigureServices(IServiceCollection services)
    {
    
        if (envirnoment.IsDevelopment())
        {
            services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
        }
        else if (envirnoment.IsStaging())
        {
            // Add Staging Connection
        }
        else
        {
            // Add Prod Connection
        }
    
    }
    
  • 0

    您也可以通过利用Environment based Startup class and methods来解决这个问题 . 所以,你可以这样做:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(Configuration.GetConnectionString("ProductionConnection")));
    }
    
    public void ConfigureStagingServices(IServiceCollection services)
    {
        services.AddDbContext<ApplicationDbContext>(options =>
                options.UseSqlServer(Configuration.GetConnectionString("StagingConnection")));
    }
    
    public void ConfigureDevelopmentServices(IServiceCollection services)
    {
        services.AddDbContext<ApplicationDbContext>(options =>
                options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
    }
    

    对于环境之间的公共服务,您可以将它们提取到私有方法中,然后在Configure Services上调用它 . 另外,请考虑在源代码管理中没有 生产环境 连接字符串 . 您可以将其设置为Environment Variable on the machine.

相关问题