IOptionsMonitor Demo – Reload Configurations In .NET Applications

IOptionsMonitor Demo – Reload Configurations In .NET Applications

The last article was dedicated to getting started on the options pattern for reading configurations in .NET applications. In this article, let’s have a look at how the configurations can be reloaded, even after the app has started. This time, we will use IOptionsMonitor interface for the demo.

Plan

  • Create a sample .NET Core MVC web application for demonstrating the concept.
  • A mail feature JSON object to be added in appsettings.json file, which is responsible for hypothetical mail feature in our demo application.
  • Then create an options class for holding these Mail Feature related settings together.
  • Then use IOptionsMonitor to access the settings.
  • Once the application is up and running, change appsettings.json to see that modified configuration is available.

Does this plan sound logical ? Let’s get started then !

Boring Important Theory

Generally, when the application is applying configurations, it should set reloadOnChange parameter to true on AddJsonFile call.

This change is not required for .NET core web applications. This is because they use CreateDefaultBuilder method to create the IWebHostBuilder, which takes care of setting the reloadOnChange parameter to true.

But let’s say if you want to use custom logic for creating IWebHostBuilder, then you should remember to use appropriate overload of AddJsonFile. OR if you want to use appsettings.json file with console application, then also you will have to appropriately load the configurations.

Beware !!!

The reloadOnChange just updates the IConfiguration object.

If we use options pattern using Bind or Get, as explained in previous post, to populate the strongly typed object, then the strongly typed object would not be updated with new values.

This is because reading from IConfiguration only happens when you call Bind or Get. After this call, if the configuration changes, the strongly typed object would never know about it.

In order to make sure that configuration reload appropriately even after app has started, it is better to wrap the options object using

  • IOptionsSnapshot which computes configurations for every request
  • OR IOptionsMonitor which is singleton and also has one additional advantage, it can provide you notification everytime configuration is update.

Let’s Code!

As stated earlier, create a .NET Core web application (MVC) using Visual Studio or dotnet command line. Then go to appsettings.json file and add the new mail feature object

Below code shows the all the contents of modified file:

{
"MailFeatureOptions": {
"IsEnabled": true,
"SmtpServer": "some-dns.smtp.local",
"FromEmailAddress": "no-reply@mysite.com",
"Subject": "Exciting Offers For Exclusively For You"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
view raw appsettings.json5 hosted with ❤ by GitHub

Options

Let’s create the Configurations directory in the web app and then add a class MailFeatureOptions. It should have read-write properties with same names as in our configuration section.

The code is shown in next code snippet.

Startup

Modify ConfigureServices method in Startup class and add below lines. The below lines read the configuration section and will enable dependency injection of IOptionsMonitor in any other class of this application.

The code is shown in next code snippet.

Home Controller

Inject the IOptionsMonitor<MailFeatureOptions> in the controller. Read the value from configuration in Index action and set it in ViewData. Then this value from ViewData can be shown on UI.

// MailFeatureOptions.cs
public class MailFeatureOptions
{
public bool IsEnabled { get; set; }
public string SmtpServer { get; set; }
public string FromEmailAddress { get; set; }
public string Subject { get; set; }
}
// Startup.cs
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
// some other code…
services.Configure<MailFeatureOptions>(Configuration.GetSection(nameof(MailFeatureOptions)));
services.AddControllersWithViews();
}
// some other code…
}
// HomeController.cs
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
private readonly IOptionsMonitor<MailFeatureOptions> mailFeatureOptionsMonitor;
public HomeController(ILogger<HomeController> logger, IOptionsMonitor<MailFeatureOptions> mailFeatureOptionsMonitor)
{
_logger = logger;
this.mailFeatureOptionsMonitor = mailFeatureOptionsMonitor;
}
public IActionResult Index()
{
// Load in ViewData
ViewData["IsEnabled"] = this.mailFeatureOptionsMonitor.CurrentValue.IsEnabled;
ViewData["SmtpServer"] = this.mailFeatureOptionsMonitor.CurrentValue.SmtpServer;
ViewData["FromEmailAddress"] = this.mailFeatureOptionsMonitor.CurrentValue.FromEmailAddress;
ViewData["Subject"] = this.mailFeatureOptionsMonitor.CurrentValue.Subject;
return View();
}
}
// Views/Home/Index.cshtml
<div class="card" style="width: 58rem;">
<div class="card-header">
MailFeatureOptions
</div>
<div class="card-body">
<ul class="list-group list-group-flush">
<li class="list-group-item text-left"><strong>IsEnabled:</strong> @ViewData["IsEnabled"]</li>
<li class="list-group-item text-left"><strong>SmtpServer:</strong> @ViewData["SmtpServer"]</li>
<li class="list-group-item text-left"><strong>FromEmailAddress:</strong> @ViewData["FromEmailAddress"]</li>
<li class="list-group-item text-left"><strong>Subject: </strong>@ViewData["Subject"]</li>
</ul>
</div>
</div>
view raw HomeController.cs hosted with ❤ by GitHub

Run the app

Now if you run the application, you should be able to view the current settings as shown below.

Options Pattern using IOptionsMonitor - Demo to reload the config settings
Options Pattern using IOptionsMonitor – Demo to reload the config settings

Change the config

Now, our application is running, so go back to appsettings.json in Visual Studio and change something from the mail feature config section. Now, if you refresh the page, you should be able to see the updated value on UI.

Wrapping Up

So, we created the .NET web application, used IOptionsMonitor to demo how the settings are automatically reloaded, when you change appsettings, even if application has already started.

Although we used MVC application for demo, the same concept applies for any .NET application including Console applications, Web APIs, Razor Views app, etc.

I hope you found this post useful. Let me know your thoughts.

Leave a Reply