I am building a web api with asp.net core and I wanted to ask how you would handle production and test environments inside the api. The goal would be to publish the web api on the IIS and then for it to use the production db connection string. When I start my api locally I would like my api to connect to the test database without me changing a lot of stuff in the code.
In my Startup.cs I use Entity Framework like this:
services.AddDbContextFactory<ProdContext>(options =>
{
string decrypted = ConnStringSecurity.Decrypt(Configuration.GetConnectionString("ProdDBConnection"));
options.UseSqlServer(decrypted,
sqlServerOptionsAction: sqlOptions =>
{
sqlOptions.EnableRetryOnFailure(
maxRetryCount: 10,
maxRetryDelay: TimeSpan.FromSeconds(5),
errorNumbersToAdd: null
);
});
});
services.AddDbContextFactory<TestContext>(options =>
{
string decrypted = ConnStringSecurity.Decrypt(Configuration.GetConnectionString("TestDBConnection"));
options.UseSqlServer(decrypted,
sqlServerOptionsAction: sqlOptions =>
{
sqlOptions.EnableRetryOnFailure(
maxRetryCount: 10,
maxRetryDelay: TimeSpan.FromSeconds(5),
errorNumbersToAdd: null
);
});
});
In the Configure method I see that you can differentiate between development and production but I can't quite imagine how the DbContexts can be integrated in the if statement:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
{
if (env.IsDevelopment())
{
//Use Test Db globally
app.UseDeveloperExceptionPage();
}
else if(env.IsProduction())
{
//Use Prod Db globally
}
}
Also in every Controller I inject the Context that I need so to make this happen I would have to check on every endpoint if I am currently in development or production. Is there a more efficient way to do this? The 'lazy' approach would be to publish two instances of my api, one for prod and one for test where the code is changed accordingly.
CodePudding user response:
You can inject IWebHostEnvironment
to the Startup
class by its constructor, which is the same one as you have among the parameters of Startup.Configure
method. Then, you can use env.IsDevelopment()
in the Startup.ConfigureServices
method, where you set up DB context.
I wonder if you really want to different DB contexts in the development and production environment.
So, having a single context MyDbContext
for both environments, Startup
class becomes like below. Then, your controllers will get MyDbContext
instance injected which connects to a different DB by the environment.
public class Startup
{
public IConfiguration Configuration { get; }
private readonly IWebHostEnvironment _env;
public Startup(IConfiguration configuration, IWebHostEnvironment env)
{
Configuration = configuration;
_env = env;
}
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<MyDbContext>(options =>
{
string decrypted = ConnStringSecurity.Decrypt(Configuration.GetConnectionString(
_env.IsDevelopment() ? "TestDBConnection" : "ProdDBConnection"));
options.UseSqlServer(decrypted,
sqlOptions =>
{
sqlOptions.EnableRetryOnFailure(
maxRetryCount: 10,
maxRetryDelay: TimeSpan.FromSeconds(5),
errorNumbersToAdd: null
);
});
});
CodePudding user response:
you can add all your sensitive key value pairs on the secrets.json when developing. the same keys in the appsetting.json will be overridden by secrets.json if they have the same key.
for production you can create application level variables by the same key value pair or use key-vault, or use app configuration if you are hosting in azure web app service.