How environment variables configuration works in dotnet core? - .net-core

In Enforce HTTPS with dotnet core, there needs to be a port specified for ssl. That port needs to be passed to the application.
See in this clear way to get a docker container to run dotnet core with ssl, one of the things we need to do is pass environment variables that the dotnet core application will use; as per the configuration system details here.
Also, in the same Enforce HTTPS with dotnet core article, you can pass something like
the useSetting()
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseSetting("HTTPS_PORT", "443")
.UseSetting("URLS", "http://+;https://+")
.UseStartup<Startup>();
Which is the same as passing ASPNETCORE_HTTPS_PORT=443 as an environment variable.
I'm really looking for where on earth I can find clear documentation on what each possible variable can be and what they do.

The settings for WebHost are well documented.

Related

What is the .NET Core way of storing application settings?

I'm developing a cross-platform (win/mac/linux) application and I'm looking to store my application state. What is the .NET Core recommended way of doing this?
I've dug through the documentation and the closest thing I found was this, which is aimed at Visual Studio/.NET Framework (and I'm on VS Code).
There are 3 ways,
ONLY For Localhost
Simply stash them in your appsettings.json or as environment
variables.
For Staging / Production,
Azure Key Vault
By utilising Azure Key Vault and the Microsoft.Extensions.Configuration.AzureKeyVault NuGet Package, you will be able to stash configurations for your projects in the best way possible in the actual environment.
You then simply inject it in,
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((context, config) =>
{
var root = config.Build();
config.AddAzureKeyVault(
$”https://{root["KeyVault:Vault"]}.vault.azure.net/",
root[“KeyVault:ClientId”],
root[“KeyVault:ClientSecret”]);
})
.UseStartup<Startup>();
Although you still have to stash those 3 variables in, Azure has Azure AD to enforce access only to specified Applications. Thus, you need to register an application under the Azure AD in order for this to work. There are also restrictive features that will help you sandbox Azure Key Vault further.
Existing Vault Storages
Last but not least, the last way is to utilise existing vault storage options like HashiCorp. Libraries like https://github.com/rajanadar/VaultSharp will help you to implement it quickly and effectively. This is suitable for you if you primarily use a non-Azure provider for your servers.
As described here, you can use appsettings.json, which is generated and referenced within the new project template in dotnet new command
You can use the ConfigurationBuilder from the Microsoft.Extensions.Configuration nuget package
Although the docs are for ASP Core, you should be able to use them in your regular .Net Core app.
Create settings.json:
{
"mysetting": "value",
}
And use it:
var configuration = new ConfigurationBuilder()
.AddJsonFile("settings.json")
.Build();
// get the values from the settings.json
var mySetting = configuration["mysetting"];
Console.WriteLine(mySetting);

Use Prometheus in .net core application

I am doing POC using Prometheus in .net core app. I did not found sufficient information on Prometheus website to get started , I have following question if someone can answer that would be helpful
a) Do I need to write my own .net core client in order to use
prometheus in app?
b) What is best approach to use prometheus for metric recording such as
should I use in every client or add prometheus logging logic in
services method so that metrics is logged for each request and
response in pipeline ?
c) where to configure prometheus server in .net core app ?
Monitor .Net core web API using prometheus
Install the below packages
<PackageReference Include="App.Metrics.AspNetCore" Version="3.2.0" />
<PackageReference Include="App.Metrics.AspNetCore.Endpoints" Version="3.2.0" />
<PackageReference Include="App.Metrics.AspNetCore.Tracking" Version="3.2.0" />
<PackageReference Include="App.Metrics.Formatters.Prometheus" Version="3.2.0" />
Add the below code in Program.cs class to support prometheus
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseMetricsWebTracking()
.UseMetrics(option =>
{
option.EndpointOptions = endpointOptions =>
{
endpointOptions.MetricsTextEndpointOutputFormatter = new MetricsPrometheusTextOutputFormatter();
endpointOptions.MetricsEndpointOutputFormatter = new MetricsPrometheusProtobufOutputFormatter();
endpointOptions.EnvironmentInfoEndpointEnabled = false;
};
})
.UseStartup<Startup>();
Make sure these below endpoints are working after making all the above changes
http://<ip:port>/metrics
http://<ip:port>/metrics-text
Add a new job in prometheus.yml
- job_name: 'SampleWebAPi'
metrics_path: /metrics-text
static_configs:
- targets: ['<ip:port>']
Restart prometheus & then check targets page
http://localhost:9090/targets
Github Code
.net client for prometheus.io now supports.NET Core 2.0:
https://github.com/prometheus-net/prometheus-net
Client is suggested here: https://prometheus.io/docs/instrumenting/clientlibs/
We are using our own open source library because no other existing solution worked correctly at the time we started using Prometheus.
https://github.com/nexogen-international/Nexogen.Libraries.Metrics
This library can add a lot of metrics out-of-the box. I recommend measuring everything you can as you can never know what will be a bottleneck in production. At least measure everything that can be a key performance indicator, like number of visitors or the time it takes to do some long operation.
The library can be configured in your ASP.NET Core Startup. I recommend injecting your metrics through an interface containing your relevant metrics.
If you have a non ASP.NET app, then you can simply set it up in your main class.
Use the this nuget library if you are using dotnet core. This will give lot of metrics out of the box.
In Configure method of startup.cs.
add app.UseHttpMetrics() after app.UseRouting. Futhermore add endpoints.MapMetrics(); as end point which expose end point to scrap prometheus metrics
Sample project here:
Repo: https://github.com/CodeSam621/YT_DotNetCorePrometheusGrafana
app.UseRouting();
app.UseHttpMetrics();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapMetrics();
endpoints.MapControllers();
});
https://www.youtube.com/watch?v=cvt1Vrs3ajU

How to get appsettings from project root to IDesignTimeDbContextFactory implementation in ASP.NET Core 2.0 and EF Core 2.0

I am building an application in ASP.NET Core 2.0 and I am having problems with EntityFramework Migrations.
I have my DbContext in a separate project (SolutionName\ProjectNamePrefix.Data) and therefore I created an implementation for the IDesignTimeDbContextFactory interface.
I wanted to use different connection strings for different environments and I need appsettings.json for that.
So after a quick search I found that I can create a new IConfigurationRoot object inside the CreateDbContext function as shown here:
https://codingblast.com/entityframework-core-idesigntimedbcontextfactory/
I added that and then for testing, tried to run dotnet ef migrations list -c MyContext from the Data project root folder.
Then I got the following error:
The configuration file 'appsettings.json' was not found and is not optional. The physical path is 'C:\dev\*SolutionName*\*ProjectNamePrefix*.Data\bin\Debug\netcoreapp2.0\appsettings.json'.
So, basically, I tried 3 options for getting the correct root path:
Directory.GetCurrentDirectory();
env.ContentRootPath; (IHostingEnvironment object, I found a way to get it here: https://github.com/aspnet/Home/issues/2194)
AppDomain.CurrentDomain.BaseDirectory;
and all of them returned the same ..\bin\debug\netcoreapp2.0\ path. When I run the Data project from VS, then the two first options give me the correct project root folder.
Is there a way to get the correct project content root folder?
Because when I added --verbose to the EF command, it logged out a row:
Using content root 'C:\dev\FitsMeIdentity\FitsMeIdentity.Data\'.
So I understand that EF somehow knows the project root but all the options mentioned above return the path for the already built application.
The only option I found that works is that I change Copy output to root folder to Copy always but found from here: https://www.benday.com/2017/02/17/ef-core-migrations-without-hard-coding-a-connection-string-using-idbcontextfactory/ that it's not a good idea.
At first I even thought about creating a Constructor for the IDesignTimeDbContextFactory implementation which gets IOptions as a parameter but that didn't work, had the same problem as explained here:
Injecting Env Conn String into .NET Core 2.0 w/EF Core DbContext in different class lib than Startup prj & implementing IDesignTimeDbContextFactory
A little late, but here is the solution for those who hate hard-coding connections strings:
internal class MigrationDbContextFactory : IDesignTimeDbContextFactory<AppDbContext>
{
public AppDbContext CreateDbContext(string[] args)
{
IConfigurationRoot configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", false)
.Build();
string connectionString = configuration.GetConnectionString("DefaultConnection");
DbContextOptionsBuilder<AppDbContext> optionsBuilder = new DbContextOptionsBuilder<AppDbContext>();
optionsBuilder.UseMySql(connectionString,
ServerVersion.AutoDetect(connectionString),
mySqlOptions =>
mySqlOptions.EnableRetryOnFailure(
maxRetryCount: 10,
maxRetryDelay: TimeSpan.FromSeconds(30),
errorNumbersToAdd: null));
return new AppDbContext(optionsBuilder.Options);
}
}
No. You can't do this, and more to the point: you're not supposed to do this. The whole entire point of IDesignTimeDbContextFactory is that it's a way to get a DbContext instance from in a context where there is no ASP.NET Core framework to work with, i.e. from a class library. If you're running migrations from an ASP.NET Core project, you don't need it, and if you're not, none of the configuration stuff is available.
Additionally, it's only to be used for development, hence the "DesignTime" part of the name. As a result, there's no need for stuff like switching between connection strings for different environments. Just hard-code the connection string as the docs detail.

.NET Core, Parallel Run of the same application with different configuration possible?

I am trying to get my head around the .netcore way of configuring an application.
Szenario:
I am running the same rest api (application) for client1 and client2 on the same server in the DEV-Environment.
We have environment specific configurations as well as client specific configurations.
"Old" Way:
With web.config transformations, I created build configurations for dev-client1 and dev-client2 and set the values accordingly...this all worked fine.
"New" Way:
As the appsettings.json depends on the windows environment variable (one per server) and therefore run into troubles. I could not find a way so far to run the apps in parallel on the same server with different configurations.
I might have missunderstood the new way of configuring an application, therefore any help would be appreciated.
in a typical new .NET Core web app, you will see this code in the Startup.cs:
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddJsonFile($"appsettings.{environment.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables()
.Build();
all you need to do is add another appsettings file with client-specific settings, like:
.AddJsonFile($"appsettings.client.json", optional: true)
then have your build script copy in the correct build configuration to appsettings.client.json. the ConfigurationBuilder will pick up the settings in all the sources and compile them into the configuration object.
also check out the full docs:
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration

Editing configuration files in Pax Exam

I am using Pax Exam to perform integration tests to my OSGi application. I have a configuration factory in which I specify the Karaf feature of my application to be installed in the test container and then modify some of a proerty of a .cfg file installed as part of my feature.
public class TestConfigurationFactory implements ConfigurationFactory {
#Override
public Option[] createConfiguration() {
return options(
karafDistributionConfiguration()
.frameworkUrl(
maven().groupId("org.apache.karaf")
.artifactId("apache-karaf")
.version("3.0.1").type("tar.gz"))
.unpackDirectory(new File("target/exam"))
.useDeployFolder(false),
keepRuntimeFolder(),
// Karaf (own) features.
KarafDistributionOption.features(
maven().groupId("org.apache.karaf.features")
.artifactId("standard").classifier("features")
.version("3.0.1").type("xml"), "scr"),
// CXF features.
KarafDistributionOption.features(maven()
.groupId("org.apache.cxf.karaf")
.artifactId("apache-cxf").version("2.7.9")
.classifier("features").type("xml")),
// Application features.
KarafDistributionOption.features(
maven().groupId("com.me.project")
.artifactId("my-karaf-features")
.version("1.0.0-SNAPSHOT")
.classifier("features").type("xml"), "my-feature"),
KarafDistributionOption.editConfigurationFilePut(
"etc/com.me.test.cfg", "key", "value"));
}
}
The property I specify in editConfigurationFilePut is modified correctly, however the rest of the .cfg file's properties are deleted. If I use the editConfigurationFilePut method to edit one of Karaf's configuration files it works as expected (just adds the new property without modifying the existing ones) so I am thinking that perhaps the problem is that Pax Exam attempts to modify the configuration before the .cfg file is installed by my feature and therefore creates a new file to put the property in. If this is the case is there some way to synchronise this process so that the .cfg file is edited only after the feature is properly installed?
There are a two different reasons for this.
1) The feature does get installed after the configfile has been "edited"
2) The feature only contains a config section and not a configfile section
I'd guess reason one is the most likely cause of this since it needs a running Karaf to install a feature through Pax Exam. So to work around reason one, replace the config with a config file present in your test project.
For reason two, make sure the feature actually does reference a config instead of a configuration admin config, or add your config to the configuration of the config-admin service. You can achieve this by injecting the ConfigAdmin service in your unit test and add your properties to the configuration pid.
EDIT:
Combine both solutions
Since because of 1) it takes longer for the config-file to be actually available, let config-admin service do the rest.
Make sure your test does retrieve the config-admin service either by injecting it or by waiting for it's availability.
Now within a #Before method make sure you wait till your config is complete and change it from there on. This way you don't need to duplicate the config files.

Resources