I've configured nlog to write logs to database, giving host for connection string from appsettings.json using config layout drawer. But there are some log calls inside Startup.ConfigureServices and Startup.Configure. So, when the configuration is not ready, nlog in this moment tries to write to database. It takes empty host (config is still not ready!), and in the nlog's own log file I see the error of failed logging because of empty host.
So, the question: is it the way not to log to database target utill the config will be ready?
I'm guessing the issue is that you start using NLog before having loaded MEL-Configuration.
The "solution" is to perform early load and setup the appsettings.json:
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
ConfigSettingLayoutRenderer.DefaultConfiguration = Configuration;
// Loads NLog.config one more time
var logger = NLog.Web.NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
See also: https://github.com/NLog/NLog.Extensions.Logging/issues/265
NLog 4.7.1 and NLog.Web.AspNetCore ver. 4.9.3 will make it possible to do this:
var logger = NLog.LogManager.Setup().LoadConfigurationFromAppSettings().GetCurrentClassLogger();
See also: https://github.com/NLog/NLog.Web/pull/540
Related
IMPORTANT: This is NOT a duplicate of How to get IConfiguration from within Main? !
I have read that topic, I have read answers and comments and NO, my case is completely different.
The exact point when I need my configuration is before invoking UseUrls from IHostBuilder.
This is invoked from Main. My URLs are defined in appsettings.json file, and now I get the configuration like this:
var configuration = (
new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true))
.Build();
But this seems wrong. I mean the framework somehow loads the configuration and injects it to the services. However, the point I need it is before the services are even configured.
I also have a special execution mode for my Main - when import command argument is used, my data context is initialized (again, using configuration from appsettings.json) to import data from external database. When this happens, no web server is started at all, the program behaves like a console application. So again, dependency injection is not available, I instantiate the configuration as described. This is well, OK, because the initialization is done only once.
However, my "hack" initializes the IConfiguration and then the framework does it again. This looks like a code smell and I wonder how to fix this.
Here's my CreateHostBuilder method:
private static IHostBuilder CreateHostBuilder(string[] args) {
var defaultBuilder = Host.CreateDefaultBuilder(args);
var configuration = (new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)).Build();
return defaultBuilder.ConfigureWebHostDefaults(webBuilder => {
webBuilder.UseStartup<Startup>().UseUrls(configuration.GetValue<string>("InternalSiteUrl"));
});
}
There is a better way, isn't it?
Web api is deployed in an on-premise web server. I have setup the release pipeline through azure devops. Now looking for a way to remove appsettings.env.json after deployment is complete
such that:
appsettings.Development.json and appsettings.Staging.json are removed from the target directory of the production environment after the app is deployed.
You can try Delete Files task.
The UI interface operation is as follows, add a Delete files from task to the Deployment group job.
And then add the files you want to delete, that is, the paths specified by appsettings.Development.json and appsettings.Staging.json.
Save and run when you are done.
As long as you have specified the Environment key in the web.config file, other files will not be included.
`
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
this.Configuration = builder.Build();
}
...`
So it would be fine even if you will not delete the other files.
In this thread I was able to setup my simple console application using ASP.NET CORE's configuration system.
The code is as simple as:
static void Main(string[] args)
{
string environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{environment}.json", optional: false)
.AddEnvironmentVariables();
config = configuration.Build();
var serviceProvider = new ServiceCollection()
.AddSingleton<IConfiguration>(config)
.AddDiscoveryClient(config)
.BuildServiceProvider();
Console.WriteLine(config["Test"]);
Console.Read();
}
However, since the application does not use IApplicationBuilder, I cannot invoke the .UseDiscoveryClient() method. I end up receiving an error on .AddDiscoveryClient(config):
"Discovery client type UNKNOWN, check configuration"
Is there a work around this? We would like to experiment using console applications with our Spring Cloud Config server. If there is no way to do it with Steeltoe, feel free to inform with other libraries that do.
The extension methods AddDiscoveryClient and UseDiscoveryClient are for use with Steeltoe service discovery. The error message you're seeing is due to Steeltoe not knowing which type of service registry your app should be a client of (ie: "client type UNKNOWN").
You only wish to access Spring Cloud Config server, so you don't need either of those methods. You can add the ConfigServerConfigurationProvider to you your config builder with .AddConfigServer.
you should add "appName" and "hostname" in the appsetting.json under instance
Hi I'm trying to write environment specific configuration for specflow test and I'm a little bit confused.
I know that in .net Core i have Environment variables and in web app i can just write this:
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
But how to use this in the library class project? My Solution is divided into a main project (class library) with specflow cases, and project that will handle the connection with DB. The connection strings have to change depending on the environment. I wanted to create appsettings.{env}.Json for each, but how can I assign appsetting file depending on env if I don't have startup class?
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.