C
Join ServerC#
help
✅ How to edit and save specific appsettings.json (project root) section?
Kkaziux1/23/2023
Hello, I have issue with editing specific section in the appsettings.json in project root folder, but now it overwrites all he file although it should overwrite only the specific section
public void SetYear(int year)
{
var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables()
.Build()
.Get<Config>();
config.ConfigurableYear = year;
var jsonWriteOptions = new JsonSerializerOptions()
{
WriteIndented = true,
};
var newJson = JsonSerializer.Serialize(config, jsonWriteOptions);
var appSettingsPath = Path.Combine(Directory.GetCurrentDirectory(), "appsettings.json");
File.WriteAllText(appSettingsPath, newJson);
}
Ttebeco1/23/2023
is that in the same application that runs ?
Ttebeco1/23/2023
or is that executed on the CI before deployment ?
Ttebeco1/23/2023
and when is
SetYear
called if that's done while the application runKkaziux1/23/2023
I use on the local env. This is service function which used on the api endpoint
Ttebeco1/23/2023
can you share a bit more ?
Ttebeco1/23/2023
what means "I use on the local env"
Ttebeco1/23/2023
do you run that BEFORE you run your app locally ?
Ttebeco1/23/2023
or is that code ran in the middle of no where while still running ?
Kkaziux1/23/2023
nope, I do just API call.
Ttebeco1/23/2023
so that code is executed inside aController action for example ?
Kkaziux1/23/2023
inside controller aka endpoint
Ttebeco1/23/2023
soooooo
Ttebeco1/23/2023
it look like you're looking for
IOptions
or IOptionsMonitor
Ttebeco1/23/2023
which most of your code above could be deleted
Ttebeco1/23/2023
and you could only stick to
options.ConfigurableYear = year
in that codeTtebeco1/23/2023
and nothing more
Ttebeco1/23/2023
you don't need to know the source of the file
Ttebeco1/23/2023
you don't need to edit the file
Ttebeco1/23/2023
IOptions
completly replace the idea of .Get<>
Ttebeco1/23/2023
as
.Get
is not super helpfull in the long runTtebeco1/23/2023
IOptions
does what .Get do but way moreTtebeco1/23/2023
like validation but also DI support
Ttebeco1/23/2023
meaning you could possibly mute the value of the property that is already in DI
Kkaziux1/23/2023
public class ConfigService : IConfigService
{
private readonly Configs _configs;
public ConfigService(IOptions<Configs> configs)
{
_configs = configs.Value;
}
public void SetYear(int year)
{
_configs.ConfigurableYear = year;
}
}
Also, I do in this Startup.cs to bind this section
services.Configure<Configs>(options => Configuration.GetSection("ConfigurableYear").Bind(options));
Ttebeco1/23/2023
$options
MMODiX1/23/2023
appsettings.json:
src/Foo/FooOptions.cs:
src/Foo/FooServiceCollectionExtensions.cs:
Program.cs / Startup.cs:
Bar.cs:
{
"My": {
"Foo": {
"Kix": 5
}
}
}
src/Foo/FooOptions.cs:
public class FooOptions
{
public const string SectionName = "My:Foo";
public string Bar {get;set;} = "default value for bar";
public int Kix {get;set;} = -1;
public DateTime? Pouet {get;set;} = default;
}
src/Foo/FooServiceCollectionExtensions.cs:
namespace Microsoft.Extensions.DependencyInjection; // <==== recommanded for service.Add so that you don't clutter Startup file
public class FooServiceCollectionExtensions
{
public static IServiceCollection AddFoo(this IServiceCollection services) =>
services
.AddOptions<FooOptions>()
.BindConfiguration(FooOptions.SectionName)
.Validate(options => options.Kix >= 0, $"The configuration key '{FooOptions.SectionName}:{nameof(Kix)}' cannot be negative")
;
public static IServiceCollection AddFoo(this IServiceCollection services, Action<FooOptions> configure) =>
services
.AddFoo()
.Configure(configure);
Program.cs / Startup.cs:
services.AddFoo();
// or
services.AddFoo(fooOptions => fooOptions.Kix = 12);
Bar.cs:
public class Bar
{
private readonly FooOptions _fooOptions;
// .Value in ctor is fine only if it's always ever a non-changing value (no reload and/or no scoped resolution)
public Bar(IOptions<FooOptions> fooOptions)
=> _fooOptions = fooOptions.Value;
}
Ttebeco1/23/2023
more like that @kaziux
Ttebeco1/23/2023
I strongly advice naming Options .... Options and not Config
Ttebeco1/23/2023
and completly avoid
ConfigService : IConfigService
Ttebeco1/23/2023
you don't create a service for that
Ttebeco1/23/2023
you just inject that options where you need it
Ttebeco1/23/2023
since you need the value to change you never store the
.Value
no whereTtebeco1/23/2023
else you're storing a value
Ttebeco1/23/2023
IOptions<FooConfigsOptions> configsoptions
Kkaziux1/23/2023
But I must have option for user aka admin to set a value
Ttebeco1/23/2023
yes
Ttebeco1/23/2023
which is unrelated to a file change
Ttebeco1/23/2023
unless you're trying to persist value for later run of the same app if you close / restart
Ttebeco1/23/2023
in such case I would advise something else than mutating the appsettings
Kkaziux1/23/2023
because one of requirements make that value editable. So system admin must change value who can be non-tech person
Ttebeco1/23/2023
should that new value be persited for later
Ttebeco1/23/2023
liek if the app crash and you restart the app
Ttebeco1/23/2023
sounds like what Azure AppConfiguration does / could do
Ttebeco1/23/2023
or a database
Ttebeco1/23/2023
file are not super suited for that
Kkaziux1/23/2023
value is must set configurable runtime
Ttebeco1/23/2023
yeah i got that
Ttebeco1/23/2023
I meant once you set it
Ttebeco1/23/2023
imagine the app crash
Ttebeco1/23/2023
and restart
Ttebeco1/23/2023
should it take the original value
Ttebeco1/23/2023
or the last changed value
Kkaziux1/23/2023
The case if for some reason you can't save the value sucessfully
Ttebeco1/23/2023
that ... doesn't answer the question sadly
Ttebeco1/23/2023
* value is 1
* start the app
* admin change value to 2 properly
* 10 minute later ...
* app crash
* app restart
what hsould be the value 1 or 2 ?
* start the app
* admin change value to 2 properly
* 10 minute later ...
* app crash
* app restart
what hsould be the value 1 or 2 ?
Kkaziux1/23/2023
That is the case I faced prieviously when value is saved on the bin/debug edition of the appsettings.json so the value be 1
Ttebeco1/23/2023
i'm not asking about past test 😄
Ttebeco1/23/2023
I'm asking about that's the actual requirement from your PO / PM
Kkaziux1/23/2023
It depends if have reload on change or not
Ttebeco1/23/2023
s;flkdgja;kjdfgha;dfkjhg
Ttebeco1/23/2023
that is not my question
Ttebeco1/23/2023
I'm asking about persistancy / resiliency over a crash
Kkaziux1/23/2023
If saved in the DB it would be fine but I'm not 100proc sure about some kind of the file
Kkaziux1/23/2023
Much safer case have custom json with user configurable values
Ttebeco1/24/2023
no it's not
Ttebeco1/24/2023
that's exactly what
Azure AppConfiguration
isTtebeco1/24/2023
Azure App Configuration provides a service to centrally manage application settings and feature flags. Modern programs, especially programs running in a cloud, generally have many components that are distributed in nature. Spreading configuration settings across these components can lead to hard-to-troubleshoot errors during an application deployment. Use App Configuration to store all the settings for your application and secure their accesses in one place.
Ttebeco1/24/2023
what you're trying to do already exists in a product
Ttebeco1/24/2023
that's why I'm hinting it at you
Ttebeco1/24/2023
it's already hot reload / plugable / editable / searchable /etc ...
Kkaziux1/24/2023
Sorry, but I'm not hosting this project on the free Azure plan
Kkaziux1/24/2023
but if hosting would be the case, I must pretty aware of that.
Ttebeco1/24/2023
look at Consul then
Ttebeco1/24/2023
it's a dynamic Key/value store thing
Ttebeco1/24/2023
with a REST api to edit/load value
Ttebeco1/24/2023
which you can run on your own infra
Ttebeco1/24/2023
and it will persist the value
Ttebeco1/24/2023
and you can load the config from it
Ttebeco1/24/2023
you'll avoid all the pain of weird magic file on disk
AAccord1/25/2023
Was this issue resolved? If so, run
/close
- otherwise I will mark this as stale and this post will be archived until there is new activity.