Contact Us

Contact Us



Pleas confirm by checkbox


Technical

Change Notifications and Named Options using Options pattern in .NET Core

Author_img
By Mohammed Moiyadi August 18, 2021

Change Notifications and Named Options using Options pattern in .NET Core

In my previous blog, I explained the process of creating strongly typed access to a group of related settings in the .NET Core using the Options pattern. I also talked about the IOptions, IOptionsSnapshot, and IOptionsMonitor interface in .Net Core. In this blog, I have moved a step ahead by diving deep into the additional features offered by IOptions on .NET Core.

Here, I am going to build the same example as discussed in my previous blog on IOptions. Before I start the process, kindly go through the blog to understand the basics of the Options pattern in .NET Core.

Quick Recap Of The Application: We have a .NET 5 Web API project with an API to generate the report. Next, send that report to some recipients with a subject that we can customize. So, we have a ReportController with a post API for the same. We have a couple of services, namely ReportService and EmailService to generate the report and send the report as an email, respectively. The EmailService is registered as Singleton scoped dependency, and it reads the configuration parameter for Subject and Recipients via IOptionsMonitor.

We will go back to having EmailOptions as the private field in EmailService rather than IOptionsMonitor<EmailOptions>. Since we are reading CurrentValue in the constructor and EmailService is a singleton service, this will give rise to the problem where the service won’t read the latest value from the configuration while the application is still running. Now, let’s fix that using the OnChange listener provided by IOptionsMonitor. In the constructor, in addition to setting the EmailOptions, we will also register an OnChange listener for IOptionsMonitor. In that listener, we will reset our field to the latest value provided by IOptionsMonitor.

EmailOptions in EmailService

Register OnChange in EmailService

Now, let us start the application and see what happens when we change configuration values. As soon as I change the configuration values and save the file, the breakpoint which I had set on the OnChange listener got hit.

Email Options modified in appsettings.json

OnChange in EmailService

Options pattern in .NET Core

Application run with Email Options modified

This is precisely what we wanted. Now, whenever EmailService’s Send method is called, we can read the latest values from the configuration. Whenever EmailOptions configuration changes, we capture the newest value in the OnChange listener. Note that the OnChange listener is only available for IOptionsMonitor and not IOptionsSnapshot, and the reason being IOptionsSnapshot never had this problem in the first place. With IOptionsSnapshot, we were already able to read the latest configuration values in our service.

Exception Scenario

Now, let us consider another scenario. If some exceptions occur in our code, we should handle them gracefully and email the administrators to let them know about the exception. And, we want to use the same EmailService to send the admin email. Let us first write some code to handle the exceptions in our code. We will add UseExceptionHandler middleware in Configure method of the Startup class and take the exception thrown from subsequent middleware in the pipeline. We can also inject IEmailService in the Configure method, which has already been registered as a dependency in the ConfigureServices process. It is this code where we will retrieve the exception details and send emails to the administrators.

Please Note: this is just an example, and it is not the standard way notifications are handled for an application.

UseExceptionHandler in Configure

Implementation

Let us now implement the SendAdmin method that we have used in Exception Handler in our EmailService. Also, let us add another section called AdminEmail to our appsettings.json file. In the SendAdmin process, we want to read from the AdminEmail section rather than the Email section of the application. Let us see how we can implement this with our existing setup?

We will create another class for AdminEmailOptions similar to EmailOptions class and then inject it the same way as EmailOptions into the EmailService.

appsettings.json with AdminEmail section

ConfigureServices in Startup.cs

IEmailService.cs

EmailService.cs

Now, we are done!

At this point, I am not very excited about this implementation as there is excessive code duplication. Surely there is a better way but first let us check that the performance works. To do this, we need to have our application throw some errors so that the Exception Handler comes into action. Let us throw an exception from ReportService and run the application.

Throwing an exception from ReportService.cs

Options pattern in .NET Core

Application running with exception thrown

As we can see, the AdminEmailOptions has correctly read the AdminEmail section of the configuration. As I mentioned earlier, there is too much code duplication with this approach. Essentially we are using the same structure of Email Options with different values at different places. We should be able to use the same class for both, which we are going to do next. So, first of all, let us get rid of the additional AdminEmailOptions class and add the section name for AdminEmail in the existing EmailOptions class.

EmailOptions.cs

Since we do not have AdminEmailOptions class anymore, we will remove its configuration in the ConfigureServices method and configure EmailOptions twice. One for the Email section and the other for AdminSection. The difference from the earlier version is that now we are passing section name as the first parameter. And this is the crux of the solution. What we have implemented here is called Named Option. We have registered two instances of EmailOptions with different names, and whenever we want to fetch the Email Options from configuration, we have to specify the name of the configuration.

Register Named Options in Startup for EmailOptions

Now, let us fix our EmailService. We don’t need AdminEmailOptions anymore. Instead, we will change the type of adminEmailOptionsVal field to EmailOptions. In the constructor, we need just one instance of IOptionsMonitor, and while setting the two areas, we need to call its Get method and pass the section’s name.

EmailService.cs

That’s it. If we run the application, we can see that both the Send method and SendAdmin method are reading the Email parameters from their respective section. Instead of throwing from ReportService, we will throw an exception from EmailService’s Send method, just after we have written to console to call both Send and SendAdmin methods in the same run.

Exception thrown from Send method of EmailService

And if we run the application now, we can see that both the Send and SendAdmin methods have picked values from their respective configuration section.

Options pattern in .NET Core

Conclusion:

So with that, we conclude the demonstration of the Options pattern in .NET Core. Options pattern is a handy feature provided in .NET Core applications, and some of the features that we have covered are:

  • Strongly-typed configurations
  • Reading configuration changes after the application starts
  • Named Options

These features are provided via IOptionsIOptionsSnapshot, and the IOptionsMonitor interface, and we should use the implementation as per the need of our application.

I hope you enjoyed reading this. Do try this method and give your reviews. Till then happy coding!

Note: The source code for this application can be found at mmoiyadi/IOptions.NetCore.

Related posts
3 Crucial Ways of Inserting Code into a Running Application without Creating Bottlenecks
Technical

3 Crucial Ways of Inserting Code into a Running Application without Creating Bottlenecks

By kulwinder.singh January 28, 2022
Apache Spark Standalone Setup On Linux/macOS
Technical

Apache Spark Standalone Setup On Linux/macOS

By kulwinder.singh October 20, 2021
Apache Flink Standalone Setup on Linux/macOS
Technical

Apache Flink Standalone Setup on Linux/macOS

By kulwinder.singh October 13, 2021
Identity, Authentication, And Access Management Using Azure Active Directory  
Technical

Identity, Authentication, And Access Management Using Azure Active Directory  

By kulwinder.singh September 22, 2021
Things to Know Before You Select A Crypto Wallet
Blockchain

Things to Know Before You Select A Crypto Wallet

By kulwinder.singh September 20, 2021
Solve 3 Most Irritating Outlook Email Rendering Issues.
Technical

Solve 3 Most Irritating Outlook Email Rendering Issues.

By kulwinder.singh September 15, 2021
Intuit Wasabi – A Scalable A/B Testing Solution
Technical

Intuit Wasabi – A Scalable A/B Testing Solution

By kulwinder.singh September 01, 2021
How To Pick The Right Data Analytics Strategy For Serverless Systems?
Big Data

How To Pick The Right Data Analytics Strategy For Serverless Systems?

By kulwinder.singh August 25, 2021
Create Strongly Typed Configurations in .NET Core
Technical

Create Strongly Typed Configurations in .NET Core

By kulwinder.singh August 13, 2021
Partitioning Database - A Divide and Rule Strategy
Technical

Partitioning Database - A Divide and Rule Strategy

By kulwinder.singh June 02, 2021

Stay updated

Get the latest creative news from Fubiz about art, design and pop-culture.