Basically you can use the Microsoft.Extensions.Configuration
but you can also make use of Microsoft.Extensions.Hosting
nuget package as well.
Here is a tested working example that handles configuration change as well.
Steps:
- Add an
appsettings.json
file to the project.
- Set
Build Action
to None
.
- Set
Copy to Output Directory
to Copy always
.
- Create a class for your options. (In this example:
SampleOptions
)
- Configure your options in
appsettings.json
.
- Add
Microsoft.Extensions.Hosting
nuget package to your project.
- Modify
Program.cs
:
- Configure and build a host. (e.g. register your forms, options into DI)
- Start host.
- Resolve
IHostApplicationLifetime
.
- Create an
IServiceScope
using host's IServiceProvider
.
- Resolve your
MainForm
.
- Call
Application.Run()
method with your resolved MainForm
instance.
- Modify
MainForm.cs
:
- Inject
IOptionsMonitor<SampleOptions>
into the .ctor
- Register a listener to be called whenever
SampleOptions
changes
using IOptionsMonitor<SampleOptions>.OnChange
method.
Here are the files.
appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information"
}
},
"SampleOptions": {
"SampleStringKey": "Sample value",
"SampleIntegerKey": 42
}
}
SampleOptions.cs
namespace WinFormsAppNet6;
public class SampleOptions
{
public string SampleStringKey { get; set; } = "N/A";
public int SampleIntegerKey { get; set; }
}
Program.cs
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace WinFormsAppNet6;
internal static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static async Task Main() // <-- 'async Task' instead of 'void'
{
// To customize application configuration such as
// set high DPI settings or default font,
// see https://aka.ms/applicationconfiguration.
ApplicationConfiguration.Initialize();
using IHost host = CreateHost();
await host.StartAsync();
IHostApplicationLifetime lifetime =
host.Services.GetRequiredService<IHostApplicationLifetime>();
using (IServiceScope scope = host.Services.CreateScope())
{
var mainForm = scope.ServiceProvider.GetRequiredService<MainForm>();
Application.Run(mainForm);
}
lifetime.StopApplication();
await host.WaitForShutdownAsync();
}
private static IHost CreateHost()
{
string[] args = Environment.GetCommandLineArgs().Skip(1).ToArray();
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddSingleton<MainForm>();
builder.Services.Configure<SampleOptions>(
builder.Configuration.GetSection(nameof(SampleOptions))
);
return builder.Build();
}
}
MainForm.cs
Controls:
Button: UpdateConfigurationButton
Button: ExitButton
RichTextBox: AppLog
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Windows.Forms;
using Microsoft.Extensions.Options;
namespace WinFormsAppNet6;
public partial class MainForm : Form
{
private readonly IOptionsMonitor<SampleOptions> optionsMonitor;
private readonly JsonSerializerOptions jsonSerializerOptions =
new(JsonSerializerDefaults.Web)
{
WriteIndented = true
};
public MainForm(IOptionsMonitor<SampleOptions> optionsMonitor)
{
InitializeComponent();
this.optionsMonitor = optionsMonitor;
optionsMonitor.OnChange(OnOptionsChange);
LogOptions(optionsMonitor.CurrentValue);
}
private void OnOptionsChange(SampleOptions options)
{
LogOptions(options);
}
private void LogOptions(
SampleOptions options,
[CallerMemberName] string? callerMemberName = null
)
{
AppendLog(
Environment.NewLine + JsonSerializer.Serialize(options),
callerMemberName
);
}
private void AppendLog(
string message,
[CallerMemberName] string? callerMemberName = null
)
{
if (AppLog.InvokeRequired)
{
AppLog.Invoke(() => AppendLog(message, callerMemberName));
return;
}
AppLog.AppendText(
$"{DateTimeOffset.Now:yyyy-MM-dd HH:mm:ss.ffffff} [{nameof(MainForm)}]::[{callerMemberName ?? "Unknown"}] {message}{Environment.NewLine}"
);
}
private void UpdateConfigurationButton_Click(object sender, EventArgs e)
{
const string AppSettingsJsonFileName = "appsettings.json";
if (!File.Exists(AppSettingsJsonFileName))
{
AppendLog(
$"{nameof(FileNotFoundException)}: {AppSettingsJsonFileName}"
);
return;
}
string jsonContent = File.ReadAllText(AppSettingsJsonFileName);
JsonNode? rootNode = JsonNode.Parse(jsonContent);
if (rootNode is null)
{
AppendLog($"{nameof(JsonException)}: File parse failed.");
return;
}
AppendLog(
$"Finding key: {nameof(SampleOptions)}:{nameof(SampleOptions.SampleStringKey)}"
);
JsonObject rootObject = rootNode.AsObject();
JsonObject? optionsObject = rootObject[nameof(SampleOptions)]?.AsObject();
if (optionsObject is null)
{
AppendLog(
$"{nameof(KeyNotFoundException)}: {nameof(SampleOptions)}:{nameof(SampleOptions.SampleStringKey)}"
);
return;
}
AppendLog(
$"Updating key: {nameof(SampleOptions)}:{nameof(SampleOptions.SampleStringKey)}"
);
optionsObject[nameof(SampleOptions.SampleStringKey)] =
JsonValue.Create(
$"Value modified at {DateTimeOffset.Now:yyyy-MM-dd HH:mm:ss.ffffff}"
);
AppendLog($"Saving file: {AppSettingsJsonFileName}");
using var stream =
new FileStream(
AppSettingsJsonFileName,
FileMode.OpenOrCreate,
FileAccess.Write,
FileShare.None
);
jsonContent = rootObject.ToJsonString(jsonSerializerOptions);
stream.Write(Encoding.UTF8.GetBytes(jsonContent));
stream.Flush();
}
private void ExitButton_Click(object? sender, EventArgs e)
{
Application.Exit();
}
}
Screenshot
