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

时间:2016-12-26 14:03:02

标签: asp.net-mvc asp.net-core

在StartUp类的ASP.Net MVC Core的配置方法中," IHostingEnvironment env"通过依赖注入传入。 并且可以基于环境做出决定。例如,

        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
        }

但是&#34; IHostingEnvironment env&#34;默认情况下不传递给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
        }

所以现在我跑的时候会收到以下错误消息:

&#34; ConfigureServices方法必须是无参数的,或者只接受IServiceCollection类型的一个参数。&#34;

ConfigureServices()不会接受IHostingEnvironment var。

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

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

实现这一目标的最佳做法是什么?

3 个答案:

答案 0 :(得分:3)

<强>更新 就像萨姆所说,乔的解决方案虽然运作正常,但这是一个黑客攻击。从ASP.Net Core 1.1开始,对不同环境使用不同连接的正确方法是从appsettings.json文件本身处理它,而不是在ConfigureServices方法中检查环境。默认情况下,该项目附带 appsettings.json appsettings.Development.json 文件(如果需要,可以使用命名约定手动创建另一个用于Staging的文件)< / p>

因此,在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文件,并且根据你是在开发环境还是已发布的生产环境中运行项目,它将使用正确的文件因此在它们中定义了设置。

答案 1 :(得分:2)

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
    }

}

答案 2 :(得分: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 {Environment} Services上调用它。另外,请考虑在源代码管理中没有生产连接字符串。您可以将其设置为Environment Variable on the machine.