How to get DotNet Core ApplicationName set by Environment Variable - asp.net-core

According to the .NET Core documentation, I should be able to set the application name using an environment variable.
Environment variable: ASPNETCORE_APPLICATIONKEY
I am not seeing this to be the case. I added the WebHostDefaults.ApplicationKey setting to the Program.cs but I am still unable to override it with an environment variable.
private static IWebHost BuildWebHost(string[] args)
{
var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("hosting.json", true)
.AddEnvironmentVariables("ASPNETCORE_")
.AddCommandLine(args)
.Build();
return WebHost.CreateDefaultBuilder(args)
.ConfigureLogging((context, builder) => { builder.ClearProviders(); })
.UseConfiguration(config)
.PreferHostingUrls(true)
.UseStartup<Startup>()
.UseSetting(WebHostDefaults.ApplicationKey, "CustomApplicationName")
.Build();
}
In startup.cs I am only seeing "CustomApplicationName" rather than the environment variable.
public class Startup
{
public Startup(IConfiguration configuration, IHostingEnvironment hostingEnvironment)
{
Configuration = configuration;
Log.Information($"Startup of application {hostingEnvironment.ApplicationName} in Environment Mode {hostingEnvironment.EnvironmentName}");
}
}
I have tried using double underscore in the environment variable name as well.
I am running on Mac OS.

As mentioned in other answers, the correct environment variable name is ASPNETCORE_APPLICATIONNAME, and it is documented here. However, it will not work, even as of .NET Core 3.1. There is a GitHub issue that describes the details of this bug, but essentially, the code inside the UseStartup<>() method sets ApplicationName back to its default value, which is the name of the assembly.
Even if you could override it back using the UseSetting() method, I wouldn't do it, based on the warnings in the discussion thread at this related GitHub issue. The safest bet for now seems to use your own separate environment variable.

I suspect this is something that the documentation "invented" and isn't actually implemented.
ASP.NET Core is hosted on github. I did a search. The only place where ASPNETCORE_APPLICATIONKEY shows up is in the documentation itself. The only issue/PR where it comes up is https://github.com/aspnet/Docs/pull/7493 which is the commit that added this environment variable to the docs and includes this insightful statement:
Did I just make up ASPNETCORE_APPLICATIONKEY? Is that a thing?

Related

ASP.net Core 2.2 configuration

Coming from a webforms background, I'm trying to understand how configuration and environment translation works in .net core 2.2 MVC web apps. Gone are the web.config files and the ConfigurationSettings.AppSettings property. I'm finding the documentation a little unclear.
The documentation states I need to call AddJsonFile or AddXmlFile during application startup. Like this:
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.SetBasePath(Directory.GetCurrentDirectory());
config.AddJsonFile(
"config.json", optional: true, reloadOnChange: true);
})
.UseStartup<Startup>();
The project template I use already has the following logic:
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
My project has appsettings.json and appsettings.development.json files. When I put a breakpoint on the Startup method of the Startup class, I can inspect the configuration parameter and see the two json configuration files exposed as what looks to be a dictionary.
Questions
So do I have to explicitly call AddJSonFile, or is this actually done for me somehow by the framework?
How do I handle transforming configuration for different deployments?
What is the best way to access this configuration in a controller?
So do I have to explicitly call AddJSonFile, or is this actually done for me somehow by the framework?
This is done in the framework. Most notably the "DefaultBuilder" adds in both appsettings.json and appsettings.{Environment}.json, among other things. https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.webhost.createdefaultbuilder?view=aspnetcore-2.2
How do I handle transforming configuration for different deployments?
You need to set the Environment variable on the host machine (This is the easiest way althought here are other ways to do it). So for example if you set the environment to be Production, then it will first load appsettings.json, then it will load appsettings.Production.json and override the default settings. More info here : https://dotnetcoretutorials.com/2017/05/03/environments-asp-net-core/
What is the best way to access this configuration in a controller?
There are two ways. You can use the Options pattern built into the framework : https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/options?view=aspnetcore-2.2
Or you can use good old fashioned POCO's (https://dotnetcoretutorials.com/2016/12/26/custom-configuration-sections-asp-net-core/).
All you need to do there is load out your configuration in your ConfigureServices method and bind it to a singleton :
services.AddSingleton(Configuration.GetSection("myConfiguration").Get<MyConfiguration>());
Then you can simply request it in your controller via DI:
public class ValuesController : Controller
{
private readonly MyConfiguration _myConfiguration;
public ValuesController(MyConfiguration myConfiguration)
{
_myConfiguration = myConfiguration;
}
}

appsettings.json file not in .net core console project

I understand that .net core has replaced the app.config file with appsetting.json. However this file seems to be added for ASP.net projects only. In fact it is not even available in the add items list.
I found this post that list packages needed to be added:
Microsoft.Extensions.Configuration
Microsoft.Extensions.Configuration.FileExtensions
Microsoft.Extensions.Configuration.Json
I added all these and it does give me the option of adding a json configuration file but still not the App Settings File which is only available under ASP.Net Core.
I am trying to understand why, doesn't a non web project need configuration and what is the recommended way to configure a .net core console application.
Thanks in advance.
Non-web project may or may not need configuration. But, as you noticed, Visual Studio doesn't scaffold console projects with appsettings.json. Obviously, you can add it to the project as json file. Once you have it, the challenge is to make use of it. I frequently use Configuration object and dependency injection in Entity Framework utilities.
For example,
public static class Program
{
private static IConfigurationRoot Configuration { get; set; }
public static void Main()
{
IConfigurationBuilder builder = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables();
Configuration = builder.Build();
IServiceCollection services = new ServiceCollection();
services.AddDbContext<MyDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddScoped<IMyService, MyService>();
IServiceProvider provider = services.BuildServiceProvider();
IMyService myService = provider.GetService<IMyService>();
myService.SomeMethod();
}
public class TemporaryDbContextFactory : IDesignTimeDbContextFactory<MyDbContext>
{
public MyDbContext CreateDbContext(string[] args)
{
IConfigurationBuilder configBuilder = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables();
IConfigurationRoot configuration = configBuilder.Build();
DbContextOptionsBuilder<MyDbContext> builder = new DbContextOptionsBuilder<MyDbContext>();
builder.UseSqlServer(configuration.GetConnectionString("DefaultConnection"));
return new MyDbContext(builder.Options);
}
}
}
This allows me to both run migrations and console-based utilities against DbContext. You don't specify what kind of configuration you are going to need - so this is just one example. But hopefully, you can adjust it to your needs.

ASP.NET Core configuration reloadOnChange with IOptionsSnapshot still not responsive

I'm using ASP.NET Core 2.0 and I have configuration code like this in the Main method:
public static void Main(string[] args)
{
var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{environment ?? "Production"}.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables()
.AddCommandLine(args)
.Build();
}
I have the reloadOnChange set to true, and in my controller I am using IOptionsSnapshot;
public HomeController(ILogger<HomeController> logger, IOptionsSnapshot<AppSettings> options)
But when I modify the values in my appsettings.json, I have to restart my app every time or the changes are not being picked up just by refreshing the browser. What am I doing wrong?
I've tried to run the app both with console and IIS Express; I've also tried IOptionsMonitor, same thing. What is the difference between IOptionsMonitor and IOptionsSnapshot?
As mentioned in the documentation, just enabling reloadOnChange and then injecting IOptionsSnapshot<T> instead of IOptions<T> will be enough. That requires you to have properly configured that type T though. Usually a configuration registration will look like this:
services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
However, looking closer at your code, it does not seem that you are using the new ASP.NET Core 2.0 way of configuring your program. The configuration is now part of dependency injection, so you will set it up as part of the WebHostBuilder, using ConfigureAppConfiguration. That could for example look like this:
public static IWebHost BuildWebHost()
=> new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.ConfigureAppConfiguration((builderContext, config) =>
{
IHostingEnvironment env = builderContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
config.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
})
.UseStartup<Startup>()
.Build();
If you are using the default builder using WebHost.CreateDefaultBuilder(), then you don’t even need to do this, as the configuration is then automatically set up like that with reloadOnChange activated.
The difference between IOptionsSnapshot and IOptionsMonitor is that the IOptionsSnapshot will just give you a snapshot of the options at the time the IOptionsSnapshot<T> object is being constructed.
That’s why the usage is exactly the same as with IOptions<T>: You inject it in the constructor and then store the options.Value in the instance to access the options later. At that point, that object is fixed and will never change. It’s just that the IOptionsSnapshot<T> is registered as a scoped dependency instead of a singleton dependency like IOptions<T>, so it gets the chance to get the current configuration values on every request instead of just once.
The IOptionsMonitor<T> however is a singleton service that allows you to retrieve the current configuration value at any given time. So it is especially useful for singleton services that need to get the current configuration whenever they need it. In addition, the options monitor offers a push mechanism to get notified of configuration changes by the configuration sources. That way, you can explicitly handle configuration changes.
Options snapshots are designed to be used for transient or scoped dependencies, so you will be fine just using those most of the time. Only in rare occasions when you have to use a singleton service that also needs to have the most updated configuration, you should have the need to use an options monitor. In those cases, note that just switching from snapshots to a monitor will not be enough. Usually, you will have to handle changed configuration in some way (for example clean up state, clear caches etc.). So you should always think about whether you actually need reloadable configuration for everything or if just restarting the application isn’t a viable alternative.

How to configure multiple ASPNETCORE_ENVIRONMENT on same machine?

I have ASP.NET core web application. I have configured the web application on our web server and set the ASPNETCORE_ENVIRONMENT variable to Development. I set this variable at machine level like shown in the picture below.
Now on the same machine i want to configured one more instance of same web application as Staging environment.
What are my options here to set ASPNETCORE_ENVIRONMENT at application level instead of machine level? so i can host multiple instances of the same application on the same machine?
You have a couple of options.
Run each app as a different user, and set the environment variable within that user profile. This gives you a nice added security bonus. You'll have to set the app pool to load the user profile.
Use IIS configuration
Start IIS manager
Choose configuration editor Pull down the section
combobox and choose system.webServer/aspNetCore
Pull down the from
combobox and choose Applicationhost.config
Click on the
environmentVariables element and click on the ... button hiding in
the second column, at the right.
Set your environment variables.
Exit out of the environment variables screen and then click Apply.
Restart the app pool/app.
Can you change the code parsing configuration running on the web server? That's what I would recommend doing. That would allow you to configure your environment more naturally in a Windows setting.
While the traditional way to configure the IHostingEnvironment.EnvironmentName variable is via the ASPNETCORE_ENVIRONMENT environment variable as you have done, you can change how ASP.NET Core parses its configuration such that you can set the variable via a command line argument.
To get into specifics...
By default, the Program.cs file emitted by the dotnet new -t web command looks something like the following:
public static void Main(string[] args) {
var host = new WebHostBuilder()
.UseKestrel()
.UseUrls("http://0.0.0.0:5000")
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
host.Run();
}
This makes ASP.NET Core use the default configuration processing (environment variables with a ASPNETCORE_ prefix) to determine the value of IHostingEnvironment.EnvironmentName, which you are using to configure how your application runs.
Fortunately, you can alter the way that ASP.NET Core parses configuration by utilizing the UseConfiguration() extension method on WebHostBuilder. Here's an example of using custom configuration with the default implementation:
public static void Main(string[] args) {
var configuration =
new ConfigurationBuilder()
.AddEnvironmentVariables("ASPNETCORE_")
.Build();
var host =
new WebHostBuilder()
.UseConfiguration(configuration)
.UseKestrel()
.UseUrls("http://0.0.0.0:5000")
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
host.Run();
}
From here, I would change it so it can use the command line in addition to the ASPNETCORE_ prefixed environment variables. This will allow you to easily run your application with whatever environment name you want, like so:
public static void Main(string[] args) {
var configuration =
new ConfigurationBuilder()
.AddEnvironmentVariables("ASPNETCORE_")
.AddCommandLine(args)
.Build();
var host =
new WebHostBuilder()
.UseConfiguration(configuration)
.UseKestrel()
.UseUrls("http://0.0.0.0:5000")
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
host.Run();
}
Then, when you start your dotnet core application with dotnet run, you can set the environment on the command line, like this:
dotnet run environment=development
dotnet run environment=staging
Now the ASPNETCORE_ENVIRONMENT environment variable will still be respected, but you can override it via the command line when you are doing local development. As a note, you will need to include the Microsoft.Extensions.Configuration.CommandLine nuget package to your project.json file if you have no already done so to get the AddCommandLine() extension method.

ASP.NET Core ignores ASPNET_ENV and Hosting:Environment

No matter when or where I set either ASPNET_ENV or Hosting:Environment the startup code will always enter
//This method is invoked when ASPNET_ENV is 'Production'
//The allowed values are Development,Staging and Production
public void ConfigureProduction(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(minLevel: LogLevel.Warning);
Configure(app);
}
What I've tried so far
Set Hosting:Environment to Development in the project properties
Set ASPNET_ENV to Development in the project properties
Set Hosting:Environment to Development in launchSettings.json
Set ASPNET_ENV to Development in launchSettings.json
Set ASPNET_ENV to Development in code via Environment.SetEnvironmentVariable("ASPNET_ENV", "Development"); in the Startup method before the call to ConfigurationBuilder.GetEnvironmentVariables()
This is version 1.0.0-rc2-20143 by the way. Am I missing something here or is it just a bug?
The environment variable name has been changed to ASPNETCORE_ENVIRONMENT as part of the name change.
It was announced in this issue and change in this PR.
If you have not done it already, try adding the environment variables to the configuration instance.
public static void Main(string[] args)
{
var builder = new ConfigurationBuilder();
builder.AddJsonFile("appsettings.json");
builder.AddEnvironmentVariables();
var config = builder.Build();
}
Whilst the answer from Henk Mollema is correct for the environment variable name, I still encountered issues where dotnetcore would seem to ignore the environment variable and use appsettings.json when run from command line.
To ensure it uses the correct environment and app settings, try the following:
Change the environment variable via Project Properties -> Debug -> Environment Variables -> ASPNETCORE_ENVIRONMENT -> Value : Change the value to match your intended environment eg Staging
Build Solution
From commandline, type SETX ASPNETCORE_ENVIRONMENT "YOUR-ENVIRONMENT-NAME" where replace "YOUR-ENVIRONMENT-NAME" to match what you set in step 1 eg Staging and ensure you include the "quotes"
IMPORTANT - make sure you all your various appsettings.json eg appsettings.staging.json is present in the project directory where you will run it. (In the case of a published solution, the appsettings.staging.json may not have been copied, so ensure it's there)
From Commandline, go to your project directory (or published directory) and run your project by typing dotnet run (or "dotnet YOURPROJECTNAME.DLL" for published projects)
Observe in the next line that appears in the commandline which states Hosting environment: YOURENVIRONMENTNAME eg Hosting environment:staging
Running a DotNetCore project from Visual Studio always picked the
correct appsettings based on the environment set in your project
properties, however these are the steps I followed to run dotnet core correctly from commandline
working correctly.
This worked for me using .net core 2.0 and building a web api. Notice the 2 different methods of accessing the environment variable.
Program.cs
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args){
if(Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT ") == "Production"){
return WebHost.CreateDefaultBuilder(args)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
} else {
return WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
}
}
But in the startup file there is another environment option
Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options => options.AddPolicy("AllowAll", p => p.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()));
var connectionString = "Data Source=tcp:<some-ip>,<some-port>;Initial Catalog=<some database>;Integrated Security=False;User Id=SA;Password=<some password>;MultipleActiveResultSets=True";
services.AddDbContext<myContext>(opt => opt.UseSqlServer(connectionString));
services.AddMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseCors("AllowAll");
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc();
}
}