C
C#17mo ago
Cotton

❔ ASP.NET Core Environment Variables in Dependency Injection

Hello, I have a (probably) slightly dumb question. What's the correct/recommended way to inject an environment variable (like from docker-compose or similar) into a service class in ASP.NET Core? Googling somehow always points me toward "multiple environments" such as test/staging/prod, but that's not what I'm looking for. My hunch is that I'm supposed to do it in Program.cs when setting up DI, somehow. In Spring I might do something like this to inject MY_ENV_VAR as a String into MyService
@Service
class MyService(@Value("${MY_ENV_VAR}") val myEnvVar: String) { ... }
@Service
class MyService(@Value("${MY_ENV_VAR}") val myEnvVar: String) { ... }
11 Replies
mindhardt
mindhardt17mo ago
I guess you are heading in the wrong direction You need it as a configuration?
phaseshift
phaseshift17mo ago
Anything in environment can be read through the IConfiguration
mindhardt
mindhardt17mo ago
Then you would need Microsoft.Extensions.Configuration And you can inhect either a strongly-typed binded Options object or directly IConfiguration
phaseshift
phaseshift17mo ago
IOptions, yes
mindhardt
mindhardt17mo ago
Thx for correcting blobthumbsup
Cotton
CottonOP17mo ago
Yeah, I ended up with something like this builder.Services.Configure<XsdPackageServiceOptions>(builder.Configuration.GetSection("XsdPackageServiceOptions")); Which is then defined in appsettings.Development.json although I haven't yet tested if actual OS environment variables would affect this at all
mindhardt
mindhardt17mo ago
Depends on your configuration setup, if you do something like .AddJsonFile().AddEnvironmentVariables() or use default host builder then you are probably fine You can add env vars in your IDE to test things
Unknown User
Unknown User16mo ago
Message Not Public
Sign In & Join Server To View
MODiX
MODiX16mo ago
appsettings.json:
{
"My": {
"Foo": {
"Kix": 5
}
}
}
{
"My": {
"Foo": {
"Kix": 5
}
}
}
src/Foo/FooOptions.cs:
public class FooOptions
{
public const string SectionName = "My:Foo";

public string Bar {get;set;} = "default value for bar";
public int Kix {get;set;} = -1;
public DateTime? Pouet {get;set;} = default;
}
public class FooOptions
{
public const string SectionName = "My:Foo";

public string Bar {get;set;} = "default value for bar";
public int Kix {get;set;} = -1;
public DateTime? Pouet {get;set;} = default;
}
src/Foo/FooServiceCollectionExtensions.cs:
namespace Microsoft.Extensions.DependencyInjection; // <==== recommanded for service.Add so that you don't clutter Startup file

public class FooServiceCollectionExtensions
{
public static IServiceCollection AddFoo(this IServiceCollection services) =>
services
.AddOptions<FooOptions>()
.BindConfiguration(FooOptions.SectionName)
.Validate(options => options.Kix >= 0, $"The configuration key '{FooOptions.SectionName}:{nameof(Kix)}' cannot be negative")
;

public static IServiceCollection AddFoo(this IServiceCollection services, Action<FooOptions> configure) =>
services
.AddFoo()
.Configure(configure);
namespace Microsoft.Extensions.DependencyInjection; // <==== recommanded for service.Add so that you don't clutter Startup file

public class FooServiceCollectionExtensions
{
public static IServiceCollection AddFoo(this IServiceCollection services) =>
services
.AddOptions<FooOptions>()
.BindConfiguration(FooOptions.SectionName)
.Validate(options => options.Kix >= 0, $"The configuration key '{FooOptions.SectionName}:{nameof(Kix)}' cannot be negative")
;

public static IServiceCollection AddFoo(this IServiceCollection services, Action<FooOptions> configure) =>
services
.AddFoo()
.Configure(configure);
Program.cs / Startup.cs:
services.AddFoo();
// or
services.AddFoo(fooOptions => fooOptions.Kix = 12);
services.AddFoo();
// or
services.AddFoo(fooOptions => fooOptions.Kix = 12);
Bar.cs:
public class Bar
{
private readonly FooOptions _fooOptions;

// .Value in ctor is fine only if it's always ever a non-changing value (no reload and/or no scoped resolution)
public Bar(IOptions<FooOptions> fooOptions)
=> _fooOptions = fooOptions.Value;
}
public class Bar
{
private readonly FooOptions _fooOptions;

// .Value in ctor is fine only if it's always ever a non-changing value (no reload and/or no scoped resolution)
public Bar(IOptions<FooOptions> fooOptions)
=> _fooOptions = fooOptions.Value;
}
Unknown User
Unknown User16mo ago
Message Not Public
Sign In & Join Server To View
Accord
Accord16mo ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.
Want results from more Discord servers?
Add your server