This is a quick tip on how to make your application reload changes made in appsettings.json using Options pattern, specifically IOptionsSnapshot. I’m using Blazor Server project for this demonstration, although this methods works in any .NET Web Application. By using Options pattern, we can force our application to use the new configuration settings without restarting our website(or server). This method only relies on page refresh.
This quick tip is similar to my previous post titled How to Access and Read Config Settings into your Blazor App, except in that example, I used IConfiguration
to read configuration settings – that method worked but did not allow my app to reload any changes made to app settings.
I was motivated to create this post in response to a question I received from a reader asking how to make app reload new settings made in appsettings.json.
Note: I did not test this with IIS, which technically, restarts(recycle) your website when config file is modified.
Content
- The problem and solution overview
- Define your config settings
- Create options pattern class
- Register your configuration
- Inject IOptionsSnapshot
- Conclusion
The problem and solution overview
The problem was that after your app has been restarted, any changes made to your appsettings.json is never reloaded on subsequent page requests.
Solution
The way to solve this is through the use of Options pattern in .NET. Specifically, we use IOptionsSnapshot to keep track of the changes made in configuration settings. The general steps in accomplishing this are:
- Define your configuration settings in appsettings.json.
- Create your options pattern class.
- Register your configuration
- Inject
IOptionsSnapshot
in your code to retrieve option settings
Define your configuration settings
In this example, I want to be able to change what the homepage is just by changing the app settings.
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AppOptions": {
"DefaultHomepage": "Counter"
},
"AllowedHosts": "*"
}
As you can see above, I defined a setting called "AppOptions"
on line 9 that defines one option setting – "DefaultHomepage"
– which, in this example, is set to "Counter"
, which means my default homepage is the Counter component of my Blazor app.
Create Options Pattern Class
The options pattern class is a class that represents these settings. According to Microsoft doc, “The options pattern uses classes to provide strongly typed access to groups of related settings.”
namespace AppSettingsDemoBlazorServer.Shared
{
public class AppOptions
{
public const string SectionName = "AppOptions";
public string? DefaultHomepage { get; set; }
}
}
In the example above, the AppOptions
class is a model for my "AppOptions"
setting in the app settings. Make sure that app settings match the read-write properties of this class. In this case, the DefaultHomepage
property of this class matched the "DefaultHomepage"
setting in the app settings.
Register your configuration
You need to register your configuration before you can use IOptionsSnapshot
anywhere in your program. In the example below, the only lines I added into my main program are lines 16-17.
using AppSettingsDemoBlazorServer.Data;
using AppSettingsDemoBlazorServer.Shared;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddSingleton<WeatherForecastService>();
//------------------------------------------------
// Register AppOptions section of appsettings.json
//------------------------------------------------
IConfiguration configuration = builder.Configuration;
builder.Services.Configure<AppOptions>(configuration.GetSection(AppOptions.SectionName));
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseRouting();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");
app.Run();
IConfiguration configuration = builder.Configuration;
builder.Services.Configure<AppOptions>(configuration.GetSection(AppOptions.SectionName));
Note: Other than line 16-17, everything you see in the main program was created for me by the .NET 6 framework.
Inject IOptionsSnapshot
After you’ve registered your configuration, you can now inject IOptionsSnapshot
in your code to retrieve a setting from appsettings.json.
@page "/"
@using Microsoft.Extensions.Options
@inject IOptionsSnapshot<AppOptions> appOptions
<PageTitle>Index</PageTitle>
@if(appOptions.Value.DefaultHomepage == "Counter")
{
<Counter />
}
else if(appOptions.Value.DefaultHomepage == "FetchData")
{
<FetchData />
}
else
{
<SurveyPrompt Title="How is Blazor working for you?" />
}
The example you see in the above code is my Index.razor, one of the components created for me by the Blazor template. Pretty much, Index component is the default homepage, as specified by the @page "/"
routing on line 1.
What I made the Index page to do, is to display a component (either Counter, FetchData, SurveyPrompt) depending on what is specified as the value of "DefaultHomepage"
in app settings.
When you run this program, the Counter component will be displayed by default because I set "DefaultHomepage"
to be "Counter"
in app settings. Try changing it to "FetchData"
, and then refresh the page, and it should now display FetchData component. Try changing the value to “” or empty string, and it should now display the SurveyPrompt component.
Conclusion
We use Options pattern, specifically, IOptionsSnapshot
or IOptionsMonitor
to keep track of changes made in appsettings.json. This allows the application to reload a new configuration on reload without a website restart.