Docker specific settings - c#

I have configurations that are environment specific. For instance, a path that I want to access when debugging the project via IIS, be in C:\MyApp\MyLocation, but when debugging the project in Docker, will be ine \app\something.
My plan was to have a specific appsettings.json for this type of build. So, where I would normally have the C:\MyApp\MyLocation in my appsettings.development.json, I would create a appsettings.docker.json, put the setting in there, and then add/change the environmental variable for "ASPNETCORE_ENVIRONMENT" to 'docker'.
However, this plan did not work, as I now get this message when I debug my app via Docker :
System.InvalidOperationException: 'Unable to configure HTTPS endpoint. No server certificate was specified, and the default developer certificate could not be found or is out of date.
To generate a developer certificate run 'dotnet dev-certs https'. To trust the certificate (Windows and macOS only) run 'dotnet dev-certs https --trust'.
For more information on configuring HTTPS see https://go.microsoft.com/fwlink/?linkid=848054.'
Is there any way I can get it work in this manner, or any other way I can docker specific configurations?

Edit:
Actually after re-reading your question and correctly reading the error, I can see that your issue has nothing to do with the configurations.
Your Asp.Net App is configured to use the developer certificate for HTTPS. Either you deactivate by removing the AddAuthentication and UseAuthentication or you have to install the certificate on the Docker image.
You can use dotnet dev-certs https in your DOCKERFILE before running your app temporarily, but in the future should create a real HTTPS certificate and configure your app correctly.
See https://learn.microsoft.com/en-us/aspnet/core/security/authentication/certauth?view=aspnetcore-3.1
You've tagged your question with .Net Core, so I guess that you're using it.
If so, you should probably be reading configurations through Configuration providers. And if your application startup is done this way:
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
It will load the json configuration provider and then the environment variables configuration provider. This means that any value that you have in your json configuration file can and will be overrided by environment variables that matches the json key correctly.
It's very easy to set environment variables when starting Docker image, and it's usually the preferred way to go when you want to set configuration of Docker images.
The hierarchy is usually set by separating the parts with __.
set MyKey="My key from Environment"
set Position__Title=Environment_Editor
set Position__Name=Environment_Rick
dotnet run
More information on the documentation.

Related

Why is HttpRepl unable to find an OpenAPI description? The command "ls" does not show available endpoints

I am working through the Microsoft Learn tutorials to "Create a web API with ASP.Net Core".
Under the heading, "Build and test the web API", at instruction (5) I am getting a response, "Unable to find an OpenAPI description".
For step (6) when executing the "ls" command I get the response, "No directory structure has been set, so there is nothing to list. Use the 'connect' command to set a directory structure based on an OpenAPI description". I have tried the "connect" command suggested here and have tried "dir" as an alternative to "ls".
I can successfully change directories in step (7) and execute the GET request for step (8) and receive the expected reply. However, it really bothers me the "ls" command is not working here and seems like an important function of the httprepl tool.
How can I get the "ls" command to work here or tell me why does it not work?
C:\Users\xxxx\source\repos\Learn\ContosoPizza>httprepl http://localhost:5000
(Disconnected)> connect http://localhost:5000
Using a base address of http://localhost:5000/
Unable to find an OpenAPI description
For detailed tool info, see https://aka.ms/http-repl-doc
http://localhost:5000/> ls
No directory structure has been set, so there is nothing to list. Use the "connect" command to set a directory structure based on an OpenAPI description.
http://localhost:5000/>
ADDED RESULTS OF SUGGESTIONS--
C:\Users\xxxx\source\repos\Learn\ContosoPizza>dotnet --version
3.1.412
C:\Users\xxxx\source\repos\Learn\ContosoPizza>dotnet add WebAPI.csproj package Swashbuckle.AspNetCore -v 5.6.3
Could not find project or directory `WebAPI.csproj`.
httprepl GitHub repo and MS Docs page
The solution for me was to simply trust localhost's SSL certification, which you can do with this command:
dotnet dev-certs https --trust
While doing the same Tutorial, a friend of mine noticed, that trusting the dev certificate, was already covered by the Tutorial, which I had overlooked doing the Tutorial myself. This is the official help site:
Trust the ASP.NET Core HTTPS development certificate on Windows and macOS.
Maybe this will still help someone with the same problem.
In step 5 HttpRepl emits the warning Unable to find an OpenAPI description, which means that it can't find the swagger endpoint, and therefore the ls command wont work.
I assume you are using VS Code and ASP.NET Core 5.0. Here is my output from running dotnet --version:
5.0.401
If we are using Visual Studio, then remember to enable swagger when you create the project - I am using Visual Studio 2019 to create the screenshot:
Specifying your OpenAPI description
To find out which endpoint to use, open the file Startup.cs and locate the code fragment that contains the text UseSwaggerUI. You should find this block of code:
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "WebAPI v1"));
}
Use the endpoint you find and run the tool like this:
httprepl http://localhost:5000 --openapi /swagger/v1/swagger.json
If you do not find any references to swagger, then see None of the above worked, swagger isn't installed below, for how to install and configure swagger for your project.
Ignoring your environment
If specifying the Open API endpoint to use doesn't work, then you are not running your Web API in a development environment. So either use a development environment, or uncomment the if-statement while testing (to setup your environment for development, see Changing your environment below):
//if (env.IsDevelopment())
//{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "WebAPI v1"));
//}
Remember to restore the code you uncommented, if any, before you deploy to production.
Changing your environment
The profile your Web API is using, is specified in the file Properties\launchSettings.json. Open the file and search for ASPNETCORE_ENVIRONMENT. Then change the instances you find to:
"ASPNETCORE_ENVIRONMENT": "Development"
If this doesn't work, or the instances were already set to "Development", it means that you are not using any of the profiles specified in your launch settings. If no profile is used, ASPNETCORE_ENVIRONMENT defaults to "Production". When using the dotnet run command, the --launch-profile parameter lets you specify which profile to use:
dotnet run --launch-profile "name_of_profile"
As a last resort you can set the environment variable ASPNETCORE_ENVIRONMENT in the shell you are using, before you run the command dotnet run:
Bash
export ASPNETCORE_ENVIRONMENT=Development
CMD
set ASPNETCORE_ENVIRONMENT=Development
PowerShell
$env:ASPNETCORE_ENVIRONMENT='Development'
Then run the application without a profile :
dotnet run --no-launch-profile
The default ports, when running without a profile, should be 5000 or 5001. But read the output from the command, to see which ports it assigns to your Web API.
Please note, if you use VS Code to run your project, that VS Code may also have created launch settings in the .vscode\launch.json. It depends on how you have configured VS Code and what you allow it to do. I found some older articles, that claim that some extensions for VS Code, may interfere with the launch settings, but they didn't specify which ones.
None of the above worked, swagger isn't installed
I none of the above worked, it means you don't have swagger installed. Install swagger for your project and when done, try again.
Package Installation
Open your project in VS Code and run the following command from the Integrated Terminal and replace WebAPI.csproj with the name of your own project file:
dotnet add WebAPI.csproj package Swashbuckle.AspNetCore -v 5.6.3
You can of course run the command from outside VS Code, with your project folder as the current working directory.
Add and configure Swagger middleware
Add the Swagger generator to the services collection in the Startup.ConfigureServices method, as the last statement in the method:
public void ConfigureServices(IServiceCollection services)
{
[... other code here ...]
// Register the Swagger generator, defining 1 or more Swagger documents
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "WebAPI", Version = "v1" });
});
}
In the Startup.Configure method, enable the middleware for serving the generated JSON document and the Swagger UI, at the top of the method:
public void Configure(IApplicationBuilder app)
{
// Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger();
// Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
// specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
});
[... other code here for setting up routing and the like ...]
}
To learn more about setting up swagger, profiles and the environment
Get started with Swashbuckle and ASP.NET Core
Managing Production and Development Settings in ASP.NET Core
Use multiple environments in ASP.NET Core
ASP.NET Core web API documentation with Swagger / OpenAPI
I had faced same issue. I have solved it by following:
In Developer PowerShell(VS 2022), Run 'dotnet run' command.
Keep this powershell as it is.
Now open new PowerShell and run "httprepl https://localhost:{PORT}"
You should be able to run api now.
You must be connected to the web server through dotnet run.

How to set ASPNETCORE_ENVIRONMENT for console application?

I have the following simple console application that contains a hosted service:
public static async Task Main(string[] args)
{
using (var host = Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
// db context
services.AddEntityFrameworkNpgsql()
.AddDbContext<ApplicationDbContext>();
// hosted services
services.AddHostedService<ConsumeScopedServiceHostedService>();
services.AddScoped<ProcessManuallySendings>();
// services
services.AddHttpClient<ISendPushService, SendPushService>(x
=>
{
x.Timeout = TimeSpan.FromSeconds(65);
});
})
.Build())
{
// Start the host
await host.StartAsync();
// Wait for the host to shutdown
await host.WaitForShutdownAsync();
}
}
}
It works with my database and it means that it requires connection string. I have three appsettings.json files:
On the development server I will use Development environment, on the production - Production. On my local machine I'm going to use Local. It's simple.
I'm going to get it with the help of ASPNETCORE_ENVIRONMENT (OS environment variable).
I use Linux and in my shell (zsh) config file I have:
When I type in my terminal $ echo $ASPNETCORE_ENVIRONMENT I have Local.
But when I start my console application
$ dotnet run // in the project folder
It's trying to start with Production environment.
See debug output:
So how to set environment? Why Os variable doesn't work?
According to the docs for .Net Core 3.0 onwards, the host configuration is provided from environment variables prefixed with DOTNET_ (for example, DOTNET_ENVIRONMENT).
If that doesn't work, you could also try setting the environment variable in the launchSettings.json like this on your profile.
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT" : "Development"
}
With .NET Core 3, the generic host uses the DOTNET_ prefix, not the old ASPNETCORE_ prefix.
When setting environment variables in rider for a console application in dotnet core 3.1, neither ASPNETCORE_ENVIRONMENT nor DOTNET_ENVIRONMENT worked regardless of whether they were set in the Run/Debug Configuration or LaunchSettings.
In my situation, I am using Microsoft.Extensions.Hosting and Microsoft.Extensions.Hosting.Abstractions and wanted hostEnvironment to be resolved correctly to Development.
if (hostEnvironment.IsDevelopment())
{
optionsBuilder.EnableSensitiveDataLogging();
optionsBuilder.AddInterceptors(new EfCommandInterceptor());
}
To get this working, I had to create an environment variable called ENVIRONMENT with the appropriate value.
ENVIRONMENT=Development

How can I get access to my docker containers environment variables in .Net Core?

I am trying to get access to some docker environment variables in my C# code running on .Net Core.
In my dockerfile generated by VS, I added environment variables like this:
ENV EnvKey = "value"
After building this image and starting the instance with the built-in Docker startup option in VS, I inspect my docker image with docker inspect MyInstance.
The resulting output lists my previously defined environment variable in "Config" -> "Env" -> "EnvKey", so I'm sure it is there.
For some testing, I try to access them with the following code:
var keys = Environment.GetEnvironmentVariables();
However, this does not retrieve the environment variable that is contained in the container.
What else do I need to configure to get this working?
The problem was very simple actually - In my case, this wasn't visible from the question.
But my real environment variable key had some "." in it. I replaced those with "_" and now it works perfectly.
If you are running an ASP.NET application, then updating the Dockerfile to ENV ASPNETCORE_EnvKey = "value" should do the trick for you.
If you are running some other .NET core app on your machine, then look at the docs here. It would seem you can't do this on the machine level, but in your RUN command, you would have to pass the 'environment variables' to the process through the dotnet command you are invoking there.

ASP.NET Core set hosting environment in build process

I have an ASP.NET Core Api where I use the appsettings.{environmentname}.json configuration files. Then I also have the appropriate launchSettings.json file with the different environment options so I can run with any specific environment settings file.
In the Startup.cs, we have a conditional setting where if we are in a non-prod environment, then we use a specific set of Jwt authentication (just has some validating checks turned off), then in prod, we load a different version that has all of the checks to turn on.
On my localhost, this works great where environment.IsDevelopment() returns true, while environment.IsProduction() returns false. Great!
But, when I run this through our build process and deploy to our test environment, the environment.IsDevelopment() now returns false.
I have added in the option in the Program.cs file to add the ConfigurationBuilder so I can pass variables to my build process, which looks like this:
dotnet restore
dotnet build --environment "Development"
dotnet publish -o ..\Artifacts
I'll post the relevant files, and the associated code for more info...
Program.cs
public static IWebHost BuildWebHost(string[] args)
{
var config = new ConfigurationBuilder()
.AddCommandLine(args)
.Build();
return WebHost.CreateDefaultBuilder(args)
.UseConfiguration(config)
.UseStartup<Startup>()
.UseNLog()
.Build();
}
Startup.cs (ConfigureServices method)
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
{
// removed code not relevant...
// options.TokenValidationParameters = Environment.IsProduction()
// options.TokenValidationParameters = Environment.IsEnvironment("Prod")
options.TokenValidationParameters = Environment.IsDevelopment()
? devTokenValidationParameters
: prodTokenValidationParameters;
// options.TokenValidationParameters = devTokenValidationParameters;
});
Why are the helper environment.Is{EnvironmentName}() checks not working here?
The environment name is runtime concept rather than a compile (or build) time concept. This means that when building (or publishing) an application the environment is not yet known and setting is has no effect. Your code is not running when you publish the application.
You can control the environment name when running the application e.g. via an argument of dotnet run:
dotnet run --environment=Production
Or using a known environment variable ASPNETCORE_ENVIRONMENT. For example by executing this at the command line:
set ASPNETCORE_ENVIRONMENT=Production
This variable might also be set using the launchSettings.json file for debugging purposes. This file is generated when creating a new project using Visual Studio or dotnet new.
The default environment for an application is Production. Please refer to the documentation for more info about this topic.

Use environment appsettings.{Environment}.json vs hardcoding in file name or db connection details in CreateHostBuilder method?

Using ef core it's possible to get everything working and run the dotnet ef migrations command line tool but Program.cs required the method
public static IHostBuilder CreateHostBuilder(string[] args)
The only thing that isn't ideal is storing database settings in a development json file then having to hardcode the development json file name in that method or hardcoding the db connection details into that method. When checking
context.HostingEnvironment.IsDevelopment() //always returns false
it is never correct or doesn't get set properly so we can't use context.HostingEnvironment.EnvironmentName as a variable either. Is there a way in the CreateHostBuilder method to load the proper app settings json file and configure/setup the environment for running the ef migrations command line tools vs hardcoding?
Yes, you have a few options to setup the Hosting Environment.
You can set a value of the DOTNET_ENVIRONMENT environment variable. This applies to all types of apps. Or you can setup ASPNETCORE_ENVIRONMENT environment variable, as this overrides the DOTNET_ENVIRONMENT when .ConfigureWebHostDefaults is called.
Another options is to set the ASPNETCORE_ENVIRONMENT value in the launchSetting.json of your project.
While you can give any value to those environment variables, the framework provides the following values: "Development", "Staging", and "Production".
You can find more information about this in the Use Multiple Environments in ASP.NET Core docs.

Categories