0

My issue is that I have a profile created that holds the environment variables that change throughout environments.

I have a profile:

"AppProfile": {
  "commandName": "Project",
  "launchBrowser": true,
  "environmentVariables": {
    "ASPNETCORE_ENVIRONMENT": "Development",
    "DB_CONNECTION": "<connection-string>",
    // ... more settings
  }
}

When I access these variables on build, I use a class with these methods:

public static string DbConnection =>
            GetEnvironmentVariable(nameof(EnvironmentVariableConstants.DB_CONNECTION));

private static string GetEnvironmentVariable(string variable)
{
    return Environment.GetEnvironmentVariable(variable, EnvironmentVariableTarget.Process) ?? "";
}

Everything runs fine when I build the project from that profile. But when I run EF Core's Add-Migration <migration-name>, an empty string is passed for my variable in Program.cs.

builder.Services.AddDbContext<ApplicationDbContext>(options =>
{
    options.UseSqlServer(EnvironmentVariables.DbConnection);
});

What could be wrong here?

I've tried setting the environment variable in nuget package manager console, and that enabled me to do a migration, but I feel like there's a better way to get this going.

We use Azure app services and set the environment variables for things like connection strings and API keys.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
  • Looks related to https://github.com/dotnet/efcore/issues/8695 and https://stackoverflow.com/questions/63486935/how-do-i-tell-a-dotnet-ef-migrations-command-point-to-a-specific-appsettings-j – Natan May 09 '23 at 23:54
  • Instead of using environment variables directly, the usual approach is to `.AddEnvironmentVariables()` to set configuration. Use the config value `ConnectionStrings.DefaultConnection` for the connection string. And maybe create separate `appsettings..json` files. https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-7.0 – Jeremy Lakeman May 10 '23 at 01:48
  • Also `Add-Migration` doesn't connect to the database, so you only need to ensure the configuration is valid. eg not-null. – Jeremy Lakeman May 10 '23 at 01:55
  • Have you tried this way `Environment.GetEnvironmentVariable("DbConnection")!`? I am getting the value as expected. – Md Farid Uddin Kiron May 10 '23 at 08:41
  • I'll try what Jeremy Lakeman and Md Farid Uddin Kiron suggested. I think Add-Migration builds the project, though. So when that happens, connectionString gets passed an empty string, and an exception is thrown. – CodeChambre May 10 '23 at 12:26
  • I guess launchSettings.json is not used when you're running command-line tools like the Entity Framework Core commands. This is why the environment variables you've set in launchSettings.json aren't available when you run Add-Migration. Instead, you can use the appsettings.json file to store configuration values like your database connection string. The appsettings.json file is read by your application at runtime, as well as by the Entity Framework Core tools. – chatay May 10 '23 at 12:31

1 Answers1

0

Take a look to IDesignTimeDbContextFactory, it's a way to manage db context at development time. I used it to set a fixed connection string to be used during development.

eg.

public class YourDbContextFactory : IDesignTimeDbContextFactory<YourDbContext> {
    public YourDbContext CreateDbContext(string[] args) {
        var optionsBuilder = new DbContextOptionsBuilder<YourDbContext>();
        optionsBuilder.UseSqlServer("<connection string here>");

        return new YourDbContext(optionsBuilder.Options); 
    }
}

For more info see Design-time DbContext Creation - Learn MS

  • Thanks, I tried this also, but it was still passing an empty string – CodeChambre May 10 '23 at 12:06
  • Ah wait my bad, I see that you're hard coding the value. want to stay away from placing as many hard coded values in the code as possible for good practice. I figured environment variables were a good way to do that. I'm still unsure if it's overkill, or if I'm using them the wrong way. I know a lot of devs put these things in appSettings.json files, but I'm difficult I guess. I might just end up putting them there and using that configuration. – CodeChambre May 10 '23 at 12:06
  • The IDesignTimeDbContextFactory is used only at design time, so you could put here a generic connection string as `Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=DevDB;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False`. This data will be never be used during runtime, and the connection string doesn't contain sensitive data, so could reside in code. – Roberto Ferraris May 10 '23 at 13:06
  • Since this code is not invoked at runtime it cannot handle appsettings. But you could also use `args` parameter. In this case you could pass this argument in such a way `Add-Migration YourMigrationName -Args "connectionstringhere"` (see [Pass arguments to IDesignTimeDbContextFactory of EF Core](https://stackoverflow.com/questions/50553481/pass-arguments-to-idesigntimedbcontextfactory-of-ef-core)). – Roberto Ferraris May 10 '23 at 13:06
  • Or you could use an environment variable and use [`Environment.GetEnvironmentVariable`](https://learn.microsoft.com/en-us/dotnet/api/system.environment.getenvironmentvariable?view=net-7.0)static method. – Roberto Ferraris May 10 '23 at 13:09