ocelot change configuration without restarting app - c#

I'm trying to change ocelot configuration without restarting app and I don't want use Consul.
Trying to search simple solution.
What I'm trying.
Registered configuration file as reloadOnChange:true
public Startup(IHostingEnvironment env)
{
var builder = new Microsoft.Extensions.Configuration.ConfigurationBuilder();
builder.SetBasePath(env.ContentRootPath)
.AddJsonFile("configuration.json", optional: false, reloadOnChange: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
And added Configuration as Singleton
services.AddSingleton<IConfiguration>(Configuration);
Also writed service which gives me ability change this singleton configuration using service.
[Route("api/[controller]")]
public class XBConfigurationController : Controller
{
public XBConfigurationController(IConfiguration configuration)
{
_configuration = configuration as IConfigurationRoot;
}
private readonly IConfigurationRoot _configuration;
// GET: /<controller>/
[HttpGet]
public IActionResult Get()
{
_configuration.Reload();
return Ok();
}
}
What's wrong? Why ocelot not refreshing it's internal configuration?

I solved my problem using administration api.
services.AddOcelot(Configuration).AddPolly().AddAdministration("/administration", "secret");
And added base url to ocelot configuration file.
"GlobalConfiguration": {
"RequestIdKey": "OcRequestId",
"AdministrationPath": "/administration",
"BaseUrl": "http://localhost:54864"
}
After changing code followed by this steps
Generate token using this service http://localhost:54864/administration/connect/token
Get current configuration using this api http://localhost:54864/administration/configuration with Get method and Bearer Token
Set modified configuration as json input to this api http://localhost:54864/administration/configuration
Additional info you can get
ocelot.postman_collection.json
Ocelot Administration Api Documentation

Related

Dependency Injection how to re-add all services to builder.Services after config change

This question is specific to NET Maui in my case.
My Settings file:
{
"MyConfig": {
"FactoryConfig1": {
"SomeType1": "SomeConfig1"
},
"FactoryConfig2": {
"SomeType2": "SomeConfig2"
}
}
}
Let's say I'm creating my services like this:
var builder = MauiApp.CreateBuilder();
builder.Services.AddSingleton<IService1, Service1>();
builder.Services.AddSingleton<IService2, Service2>();
builder.Services.AddTransient<Service3>();
// and config file-- how to modify this to use IOptions to use with IOptions Monitor?
var a = Assembly.GetExecutingAssembly();
using var stream = a.GetManifestResourceStream("MauiBlazorTestApp.appsettings.json");
var config = new ConfigurationBuilder()
.AddJsonStream(stream)
.Build();
builder.Configuration.AddConfiguration(config);
return builder.Build();
then in another class I get the config:
public class Service1 : IService1
{
IConfiguration _configuration;
public Service1(IConfiguration configuration)
{
_configuration = configuration;
}
public void SomeMethod()
{
var myConfig = _configuration.GetRequiredSection("MyConfig").Get<MyConfig>();
}
}
In each of the services, I'm injecting an IConfiguration with the configuration parameters used in each service from an appsettings.json file.
The code above works the way it is but what if sometime after starting the app, and after the services have been already created with the existing settings, the user changes some settings in appsettings.json from a UI dashboard page, how can I reload all those services with the new config settings for each...
I have to clear the services, and re-add them, is this possible, in a class outside program.cs?
It would work if I restart the application, but can it be done without, just a refresh of the DI?
As #Nkosi mentioned in the comments you should always use option pattern and not directly access the IConfiguration object.
In your case just use a class to store the desired values from configuration:
public class MyConfig
{
// The class to bind IConfiguration to
public string YourSetting { get; set; }
}
add options to the service collection and configure them. Also note the reloadOnChange parameter used during setup which indicates whether the configuration is reloaded if the file changes.
//...
builder.Configuration
.AddJsonFile("MauiBlazorTestApp.appsettings.json", optional: false, reloadOnChange: true);
// Add and configure your options
builder.Services.AddOptions();
builder.Services.Configure<MyConfig>(builder.Configuration.GetRequiredSection("MyConfig"));
//...
and finally inject the options into the target services and access the settings as needed.
public class Service1 : IService1
{
private readonly IOptionsMonitor<MyConfig> _options;
public Service1(IOptionsMonitor<MyConfig> options)
{
_options = options;
}
public void SomeMethod()
{
// Read the current value provided via IConfiguration
MyConfig appSettings = _options.CurrentValue;
var value = appSettings.YourSetting;
//...use setting as needed
}
}
When ever the current setting is requested, it will pull the latest version from settings, even if the service is a singeton.
For more information you can find this pattern very well documented here and especially for the IOptionsMonitor here

How to configure options sometime later at runtime?

I have a .Net 5 Web Api project and want to configure options with some logic. That's why I would like to move the configuration out from the Startup.ConfigureServices method and put them into their own service configurator (running during startup). So I came up with this
class OptionsConfigurator : IHostedService
{
private readonly IServiceCollection _serviceCollection;
public StartupOptionsConfigurator(IServiceCollection serviceCollection)
{
_serviceCollection = serviceCollection;
}
public Task StartAsync(CancellationToken cancellationToken)
{
/*
Build the ServiceProvider from the _serviceCollection
Get the IConfiguration service from the ServiceProvider
Read the configurationSection from the IConfiguration
call _serviceCollection.Configure<MyOptions>(configurationSection);
*/
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
This won't work because I can't inject IServiceCollection to the constructor. Is there a way to configure those options without the need of an instance of IServiceCollection?
I can provide another example showing the problem:
Your Api provides a single endpoint to update a specific configuration to change it during runtime (maybe change the database connection string for some reasons).
Create a new Web Api project
Create an options class
.
public class MyOptions
{
public string Text { get; set; }
}
Create a controller
.
[ApiController]
[Route("[controller]")]
public class MyController : ControllerBase
{
private readonly IOptionsMonitor<MyOptions> _myOptionsMonitor;
private readonly IServiceCollection _serviceCollection;
public MyController(IOptionsMonitor<MyOptions> myOptionsMonitor, IServiceCollection serviceCollection)
{
_myOptionsMonitor = myOptionsMonitor;
_serviceCollection = serviceCollection;
}
[HttpPatch]
public IActionResult UpdateOptions([FromBody] string text)
{
Console.WriteLine("Before: " + JsonSerializer.Serialize(_myOptionsMonitor.CurrentValue));
_serviceCollection.Configure<MyOptions>(x => { x.Text = text; });
string newConfig = JsonSerializer.Serialize(_myOptionsMonitor.CurrentValue);
Console.WriteLine("After: " + newConfig);
return Ok(newConfig);
}
}
Call the patch endpoint with a new configuration string in the request body. As expected this doesn't work neither, the injection of IServiceCollection is not possible and throws an exception.
Are there any solutions on how to configure options later on?
Reconfiguring options using IServiceCollection.Configure is not possible after initialization because BuildServiceProvider has already been called. You cannot configure or add any service outside program initialiazation.
To change configuration values you just need to update appsettings.json file in UpdateOptions action and to use IOptionsMonitor everywhere.
When configuring configuration you can specify to reload the configuration file when it changes. In Program.CreateHostBuilder:
public static IHostBuilder CreateHostBuilder(string[] args)
{
return Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
.ConfigureAppConfiguration((hostingConext, configurationBuilder) =>
{
configurationBuilder.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
configurationBuilder.AddJsonFile($"appsettings.{hostingConext.HostingEnvironment.EnvironmentName}.json", optional: false, reloadOnChange: true);
configurationBuilder.AddUserSecrets(Assembly.GetExecutingAssembly(), true, true);
});
}
In this way IOptionsMonitor<TOptions>.CurrentValue will always return the value stored in the configuration file even if it changes.
It sounds like you should implement your own ConfigurationProvider. This would allow you to react to changes in your configuration and then you use IOptionsMonitor (for singleton services) or IOptionsSnapshot (for transient or scoped services) to read the values.
There is a sample implementation for a database based configuration provider over at learn.microsoft.com. That would be fairly easy to change to something where you store the values in memory (or wherever you want if you want to persist changes) and then you could expose this to your controller.

Asp.net Core: middleware to controller conversion issue?

I have a Swagger project where I'm doing OAuth (token provider + verification). Everything is working fine, but the token provider was implemented as middleware based on a sample I found online. I want to convert the token provider middleware to a controller so it shows up in Swagger and users quit bugging me on how to get a token :).
In the startup.cs, I created a TokenProviderOptions object and populated it with values that live in the startup.cs (since they also get passed to the oauth verification part). I was then doing:
app.UseMiddleware<TokenProviderMiddleware>(Options.Create(tokenProviderOptions));
and the middleware was getting the options.
Now that I'm getting rid of the middleware, how can I pass in the tokenProvider options to the controller? Seems kind of weird to put it in DI as a singleton.
You can resolve options from the dependency injection container in controllers and other services using the IOptions<T> interface. For example:
public class TokenProviderController
{
private readonly IOptions<TokenProviderOptions> _options;
public TokenProviderController(IOptions<TokenProviderOptions> options)
{
_options = options;
}
}
You can then access the options values using _options.Value.
The options can be configured in the startup class. Typically you populate them from configuration:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
private IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.Configure<TokenProviderOptions>(Configuration);
}
// ...
}
If your options consist of hard-coded values, you can use a delegate to configure the binding:
services.Configure<TokenProviderOptions>(o =>
{
o.Foo = "Bar";
});
For more info check out the documentation on the options pattern.

custom keys in appSettings.json not working in ASP.NET Core 2.0

I added a CustomSettings section keys in appSettings.json in ASP.NET Core project:
{
"ConnectionStrings": {
"DefaultConnectionString": "Data Source=..."
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Warning"
}
},
"CustomSettings": {
"Culture": "es-CO"
}
}
I've not been able to load Culture key in following controller:
public AccountController(
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager,
IEmailSender emailSender,
ILogger<AccountController> logger,
IConfiguration configuration)
{
Response.Cookies.Append(
CookieRequestCultureProvider.DefaultCookieName,
CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(configuration.GetSection("CustomSettings")["Culture"])),
new CookieOptions { Expires = DateTimeOffset.UtcNow.AddYears(1) }
);
}
No matter if I do following, always they return NULL:
configuration.GetSection("CustomSettings")["Culture"];
configuration.GetSection("CustomSettings").GetValue("Culture");
I tried help based in ASP.NET Core: Step by Step Guide to Access appsettings.json in web project and class library and I've created CustomSettings class with string Culture property and injecting in Startup as follows:
// Load Custom Configuration from AppSettings.json
services.Configure<Models.CustomSettings>(Configuration.GetSection("CustomSettings"));
Accesing by inject IOptions customSettings, the value of
customSettings.Value.Culture returns NULL.
First Question: ¿What am I doing wrong or what is missing?
Second Question: ¿Why doing following in Index of HomeController throws an exception?
public class HomeController : Controller
{
public IActionResult Index(IConfiguration configuration)
{
}
}
Exception:
An unhandled exception occurred while processing the request.
InvalidOperationException: Could not create an instance of type 'Microsoft.Extensions.Options.IOptions`1[[OmniMerchant.Models.CustomSettings, OmniMerchant, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]'. Model bound complex types must not be abstract or value types and must have a parameterless constructor.
Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexTypeModelBinder.CreateModel(ModelBindingContext bindingContext)
Third Question: I need to set Culture from Starting for all the app in background based on Culture property on appSettings.json, I read MSDN documentation, but I've not been able to achieve that, ¿How can I achieve this?
Thanks
First create the modal that matches the appsetting section
public class CustomSettings
{
public string Culture { get; set; }
}
Then register it in the ConfigureServices method in Startup.cs
services.Configure<CustomSettings>(Configuration.GetSection("CustomSettings"));
Then inject it using IOptions where its needed
AccountController(IOptions<CustomSettings> settings)
{
_settings = settings.Value;
}
Why configuration section values are null?
By default there are two config files. For Release build and one for Debug. Have you checked that you actually editing the correct one (probably appsettings.Development.json)
Why DI is not working.
In .NET Core basically you can use DI in two ways. By injecting it in constructor or directly in method. In the second option you have to use special attribute [FromServices]
In your application properties -> Debug section -> Environment variables
If this is set
ASPNETCORE_ENVIRONMENT: Development
It will use appsettings.Development.json
TL:DR; Your appsettings.json file needs to be in the same working directory as your dll file.
You need to make sure that you are running the app from it's working directory.
For example, if your dll's are built to the bin folder, the following won't work:
cd bin
dotnet run app.dll
Because the appsettings.json file is not in the same folder as the dll that you are running from.
However if you are in the directory that the appsettings.json file is in, the current working directory will be set and that file will be read.
dotnet run bin/app.dll
If using VS Code launch.json you can set the cwd property to achieve this.
I had problems reading from different configuration files until I added each of them specifically in the Startup constructor like below:
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json") //***
.AddJsonFile("appsettings.development.json") //***
.AddEnvironmentVariables();
Configuration = builder.Build();
}
This is a bug I think but probably you can solve it by setting "HostingEnvironment.ContentRootPath" manualy.
Try to add the following code in the Startup method in Startup.cs:
if (env.EnvironmentName== "Production")
{
env.ContentRootPath = System.IO.Directory.GetCurrentDirectory();
}
or hardcode path like this:
if (env.EnvironmentName == "Production")
{
env.ContentRootPath = "/var/aspnetcore/...";
}
For example if your files located in "/var/aspnetcore/my_ASP_app", the startup method should be something like this:
public Startup(IHostingEnvironment env)
{
if (env.EnvironmentName== "Production")
{
//env.ContentRootPath = "/var/aspnetcore/my_ASP_app";
env.ContentRootPath = System.IO.Directory.GetCurrentDirectory();
}
//env.ContentRootPath = System.IO.Directory.GetCurrentDirectory();//you can write this line outside of IF block.
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile("appsettings.Production.json", optional: true, reloadOnChange: true);
Configuration = builder.Build();
}
It is better to use Directory.GetCurrentDirectory() instead of hardcoding.
This worked for me in Linux Ubuntu with nginx, but I don't know if it is applicable for your enviornment.

How do I access Configuration in any class in ASP.NET Core?

I have gone through configuration documentation on ASP.NET core. Documentation says you can access configuration from anywhere in the application.
Below is Startup.cs created by template
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
if (env.IsEnvironment("Development"))
{
// This will push telemetry data through Application Insights pipeline faster, allowing you to view results immediately.
builder.AddApplicationInsightsSettings(developerMode: true);
}
builder.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddApplicationInsightsTelemetry(Configuration);
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, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseApplicationInsightsRequestTelemetry();
app.UseApplicationInsightsExceptionTelemetry();
app.UseMvc();
}
}
So in Startup.cs we configure all the settings, Startup.cs also has a property named Configuration
What I'm not able to understand how do you access this configuration in controller or anywhere in the application? MS is recommending to use options pattern but I have only 4-5 key-value pairs so I would like not to use options pattern. I just wanted to have access to Configuration in application. How do I inject it in any class?
Update
Using ASP.NET Core 2.0 will automatically add the IConfiguration instance of your application in the dependency injection container. This also works in conjunction with ConfigureAppConfiguration on the WebHostBuilder.
For example:
public static void Main(string[] args)
{
var host = WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(builder =>
{
builder.AddIniFile("foo.ini");
})
.UseStartup<Startup>()
.Build();
host.Run();
}
It's just as easy as adding the IConfiguration instance to the service collection as a singleton object in ConfigureServices:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IConfiguration>(Configuration);
// ...
}
Where Configuration is the instance in your Startup class.
This allows you to inject IConfiguration in any controller or service:
public class HomeController
{
public HomeController(IConfiguration configuration)
{
// Use IConfiguration instance
}
}
The right way to do it:
In .NET Core you can inject the IConfiguration as a parameter into your Class constructor, and it will be available.
public class MyClass
{
private IConfiguration configuration;
public MyClass(IConfiguration configuration)
{
ConnectionString = new configuration.GetValue<string>("ConnectionString");
}
Now, when you want to create an instance of your class, since your class gets injected the IConfiguration, you won't be able to just do new MyClass(), because it needs a IConfiguration parameter injected into the constructor, so, you will need to inject your class as well to the injecting chain, which means two simple steps:
1) Add your Class/es - where you want to use the IConfiguration, to the IServiceCollection at the ConfigureServices() method in Startup.cs
services.AddTransient<MyClass>();
2) Define an instance - let's say in the Controller, and inject it using the constructor:
public class MyController : ControllerBase
{
private MyClass _myClass;
public MyController(MyClass myClass)
{
_myClass = myClass;
}
Now you should be able to enjoy your _myClass.configuration freely...
Another option:
If you are still looking for a way to have it available without having to inject the classes into the controller, then you can store it in a static class, which you will configure in the Startup.cs, something like:
public static class MyAppData
{
public static IConfiguration Configuration;
}
And your Startup constructor should look like this:
public Startup(IConfiguration configuration)
{
Configuration = configuration;
MyAppData.Configuration = configuration;
}
Then use MyAppData.Configuration anywhere in your program.
Don't confront me why the first option is the right way, I can just see experienced developers always avoid garbage data along their way, and it's well understood that it's not the best practice to have loads of data available in memory all the time, neither is it good for performance and nor for development, and perhaps it's also more secure to only have with you what you need.
I know this is old but given the IOptions patterns is relatively simple to implement:
Class with public get/set properties that match the settings in the configuration
public class ApplicationSettings
{
public string UrlBasePath { get; set; }
}
register your settings
public void ConfigureServices(IServiceCollection services)
{
...
services.Configure<ApplicationSettings>(Configuration.GetSection("ApplicationSettings"));
...
}
inject via IOptions
public class HomeController
{
public HomeController(IOptions<ApplicationSettings> appSettings)
{ ...
appSettings.Value.UrlBasePath
...
// or better practice create a readonly private reference
}
}
I'm not sure why you wouldn't just do this.
There is also an option to make configuration static in startup.cs so that what you can access it anywhere with ease, static variables are convenient huh!
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
internal static IConfiguration Configuration { get; private set; }
This makes configuration accessible anywhere using Startup.Configuration.GetSection... What can go wrong?
I'm doing it like this at the moment:
// Requires NuGet package Microsoft.Extensions.Configuration.Json
using Microsoft.Extensions.Configuration;
using System.IO;
namespace ImagesToMssql.AppsettingsJson
{
public static class AppSettingsJson
{
public static IConfigurationRoot GetAppSettings()
{
string applicationExeDirectory = ApplicationExeDirectory();
var builder = new ConfigurationBuilder()
.SetBasePath(applicationExeDirectory)
.AddJsonFile("appsettings.json");
return builder.Build();
}
private static string ApplicationExeDirectory()
{
var location = System.Reflection.Assembly.GetExecutingAssembly().Location;
var appRoot = Path.GetDirectoryName(location);
return appRoot;
}
}
}
And then I use this where I need to get the data from the appsettings.json file:
var appSettingsJson = AppSettingsJson.GetAppSettings();
// appSettingsJson["keyName"]
I know there may be several ways to do this, I'm using Core 3.1 and was looking for the optimal/cleaner option and I ended up doing this:
My startup class is as default
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.AddControllers();
}
My appsettings.json is like this
{
"CompanySettings": {
"name": "Fake Co"
}
}
My class is an API Controller, so first I added the using reference and then injected the IConfiguration interface
using Microsoft.Extensions.Configuration;
public class EmployeeController
{
private IConfiguration _configuration;
public EmployeeController(IConfiguration configuration)
{
_configuration = configuration;
}
}
Finally I used the GetValue method
public async Task<IActionResult> Post([FromBody] EmployeeModel form)
{
var companyName = configuration.GetValue<string>("CompanySettings:name");
// companyName = "Fake Co"
}
I looked into the options pattern sample and saw this:
public class Startup
{
public Startup(IConfiguration config)
{
// Configuration from appsettings.json has already been loaded by
// CreateDefaultBuilder on WebHost in Program.cs. Use DI to load
// the configuration into the Configuration property.
Configuration = config;
}
...
}
When adding Iconfiguration in the constructor of my class, I could access the configuration options through DI.
Example:
public class MyClass{
private Iconfiguration _config;
public MyClass(Iconfiguration config){
_config = config;
}
... // access _config["myAppSetting"] anywhere in this class
}
In 8-2017 Microsoft came out with System.Configuration for .NET CORE v4.4. Currently v4.5 and v4.6 preview.
For those of us, who works on transformation from .Net Framework to CORE, this is essential. It allows to keep and use current app.config files, which can be accessed from any assembly. It is probably even can be an alternative to appsettings.json, since Microsoft realized the need for it. It works same as before in FW. There is one difference:
In the web applications, [e.g. ASP.NET CORE WEB API] you need to use app.config and not web.config for your appSettings or configurationSection. You might need to use web.config but only if you deploying your site via IIS. You place IIS-specific settings into web.config
I've tested it with netstandard20 DLL and Asp.net Core Web Api and it is all working.
Using the Options pattern in ASP.NET Core is the way to go. I just want to add, if you need to access the options within your startup.cs, I recommend to do it this way:
CosmosDbOptions.cs:
public class CosmosDbOptions
{
public string ConnectionString { get; set; }
}
Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
// This is how you can access the Connection String:
var connectionString = Configuration.GetSection(nameof(CosmosDbOptions))[nameof(CosmosDbOptions.ConnectionString)];
}
I have to read own parameters by startup.
That has to be there before the WebHost is started (as I need the “to listen” url/IP and port from the parameter file and apply it to the WebHost). Further, I need the settings public in the whole application.
After searching for a while (no complete example found, only snippets) and after various try-and-error's, I have decided to do it the “old way" with an own .ini file.
So.. if you want to use your own .ini file and/or set the "to listen url/IP" your own and/or need the settings public, this is for you...
Complete example, valid for core 2.1 (mvc):
Create an .ini-file - example:
[Startup]
URL=http://172.16.1.201:22222
[Parameter]
*Dummy1=gew7623
Dummy1=true
Dummy2=1
whereby the Dummyx are only included as example for other date types than string (and also to test the case “wrong param” (see code below).
Added a code file in the root of the project, to store the global variables:
namespace MatrixGuide
{
public static class GV
{
// In this class all gobals are defined
static string _cURL;
public static string cURL // URL (IP + Port) on that the application has to listen
{
get { return _cURL; }
set { _cURL = value; }
}
static bool _bdummy1;
public static bool bdummy1 //
{
get { return _bdummy1; }
set { _bdummy1 = value; }
}
static int _idummy1;
public static int idummy1 //
{
get { return _idummy1; }
set { _idummy1 = value; }
}
static bool _bFehler_Ini;
public static bool bFehler_Ini //
{
get { return _bFehler_Ini; }
set { _bFehler_Ini = value; }
}
// add further GV variables here..
}
// Add further classes here...
}
Changed the code in program.cs (before CreateWebHostBuilder()):
namespace MatrixGuide
{
public class Program
{
public static void Main(string[] args)
{
// Read .ini file and overtake the contend in globale
// Do it in an try-catch to be able to react to errors
GV.bFehler_Ini = false;
try
{
var iniconfig = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddIniFile("matrixGuide.ini", optional: false, reloadOnChange: true)
.Build();
string cURL = iniconfig.GetValue<string>("Startup:URL");
bool bdummy1 = iniconfig.GetValue<bool>("Parameter:Dummy1");
int idummy2 = iniconfig.GetValue<int>("Parameter:Dummy2");
//
GV.cURL = cURL;
GV.bdummy1 = bdummy1;
GV.idummy1 = idummy2;
}
catch (Exception e)
{
GV.bFehler_Ini = true;
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("!! Fehler beim Lesen von MatrixGuide.ini !!");
Console.WriteLine("Message:" + e.Message);
if (!(e.InnerException != null))
{
Console.WriteLine("InnerException: " + e.InnerException.ToString());
}
Console.ForegroundColor = ConsoleColor.White;
}
// End .ini file processing
//
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>() //;
.UseUrls(GV.cURL, "http://localhost:5000"); // set the to use URL from .ini -> no impact to IISExpress
}
}
This way:
My Application config is separated from the appsettings.json and I
have no sideeffects to fear, if MS does changes in future versions ;-)
I have my settings in global variables
I am able to set the "to listen url" for each device, the applicaton run's on (my dev machine, the intranet server and the internet server)
I'm able to deactivate settings, the old way (just set a * before)
I'm able to react, if something is wrong in the .ini file (e.g. type mismatch)
If - e.g. - a wrong type is set (e.g. the *Dummy1=gew7623 is activated instead of
the Dummy1=true) the host shows red information's on the console
(including the exception) and I' able to react also in the
application (GV.bFehler_Ini ist set to true, if there are errors with
the .ini)

Categories

Resources