Provide default configuration to your .NET applications
Time to read: 4 minutes
In a previous post I shared how you can better configure your .NET applications for Twilio and SendGrid using the Microsoft.Extensions.Configuration
APIs. In this tutorial, I'll build upon the techniques from those tutorials and you'll learn how to store default options in one section of your configuration and override them with specific options from another section. Let me clarify using an example. Applications often send different types of emails, like welcome emails, password reset emails, offer emails, etc. Depending on the type of email, you may want to send them from a different email address. For most emails, you may be using something like 'no-reply@yourdomain.tld', but for offer emails, the replies to the email could be of value. So instead of using the same no-reply address, you could use an email address that will be routed to a sales person and maybe automatically integrates with a Customer Relationship Management (CRM) system.
In this example, you'd want to store 'no-reply@yourdomain.tld' as the default reply address, but for offer-emails, you want to use another email address, for example, 'offers@yourdomain.tld'.
Prerequisites
To follow along, I recommend having
- Some experience with C# and .NET
- An OS that supports .NET (Windows/macOS/Linux)
- Git CLI
- .NET 6 SDK (older or newer should work too)
- A code editor or IDE (I recommend VS Code with the C# plugin, Visual Studio, or JetBrains Rider)
You can find the source code for this tutorial on GitHub. Use it as a reference if you run into any issues, or submit an issue if you need assistance.
Getting started
You can apply these concepts to any scenario, but let's continue using the email scenario throughout this tutorial.
Run the following commands to clone the tutorial project to your machine using git and navigate into the project:
The git repository you cloned contains a .NET 6 console application that already contains some JSON configuration and code to load the configuration.
Here's what the appsettings.json file looks like:
Here's what the Program.cs file looks like:
The code builds configuration using only JSON as a source and then the GetEmailOptions
local function is used to fetch the configuration and create an instance of EmailOptions
for the welcome-email, password-reset-email, and offer-email. You would probably dynamically generate the body of the emails and dynamically fetch the recipient email address in a real application, but this will work fine for the purpose of this tutorial.
After each EmailOptions
object is created for each email section, the configuration is logged via the LogEmailOptions
local function, so you can see the result of this code.
You may notice that there's a lot of redundancy in the JSON, which is why you'll introduce a defaults section in the next part of this tutorial.
Run the project using the .NET CLI:
You can see that the configuration is pulled from the JSON file and then written to the console.
Add a defaults section for redundant configuration elements
You can add a Defaults
section to remove the redundant configuration elements. Open appsettings.json and in front of the Welcome
section, add a Defaults
section:
As shown above, also remove the redundant FromEmail
, FromName
, ToEmail
, and ToName
properties from the Welcome
and PasswordReset
section. However, only remove the redundant ToEmail
and ToName
properties from the Offer
section and leave the FormEmail
and FromName
properties be.
Now, update the code in the Program.cs file so that the configuration is retrieved from the specific email section, but if null (??
), then retrieve it from the Defaults
section.
Run the project again using the .NET CLI:
As you can see, the output has not changed, but now you can set configuration on specific sections and fallback on configuration from the Defaults
section.
This code gets the job done, but the same result could be achieved more eloquently by binding configuration sections to strongly-typed objects.
Bind defaults and override defaults using the configuration binder
Instead of retrieving each configuration element individually, you can use the configuration binder to bind configuration sections to strongly-typed objects. There are two methods you can use to bind configuration sections to an instance of EmailOptions
: Get<T>()
and Bind(object)
.
To use the Get
method, pass in the desired type as a generic type parameter and the Get
method create an instance of that type and bind the configuration to the object.
To use the Bind
method, create an instance of EmailOptions
and then pass it as a parameter to the Bind
method.
What's even more interesting is that you can use the Bind
method multiple times! So, if you'd like to bind both the defaults and the email specific configuration, you could do that as follows:
Using this technique, update the GetEmailOptions
local function to create an instance of EmailOptions
, then bind the Defaults
section to it, and then override the defaults by binding the specific section to it:
Hardcoding defaults
In addition to pulling defaults from the configuration, you may also opt to add default values directly into your code. For example, if you're developing a library for others to consume, it would be convenient for some of the configuration elements to have default values.
If you're pulling individual configuration elements, you could add default values like this:
Maybe it doesn't make sense to hardcode a default value, but the configuration element is required, so you want to throw an exception if the configuration element is null
. In that case, you can also use the null-coalescing operator to throw an exception inline like this:
However, if you're using the configuration binder, you don't need to use the null-coalescing operator, and you can instead specify the default values in the object initializer like this:
Alternatively, you could specify default values in the class definition itself like this:
Next steps
You've learned how to provide default configuration values through code and through a dedicated Defaults
configuration section. If you haven't already, I recommend learning about more configuration techniques in a tutorial applied to Twilio configuration, or applied to SendGrid configuration.
If you found this useful, let me know and share what you're working on. I can't wait to see what you build!
Niels Swimberghe is a Belgian American software engineer and technical content creator at Twilio. Get in touch with Niels on Twitter @RealSwimburger and follow Niels' personal blog on .NET, Azure, and web development at swimburger.net.
Related Posts
Related Resources
Twilio Docs
From APIs to SDKs to sample apps
API reference documentation, SDKs, helper libraries, quickstarts, and tutorials for your language and platform.
Resource Center
The latest ebooks, industry reports, and webinars
Learn from customer engagement experts to improve your own communication.
Ahoy
Twilio's developer community hub
Best practices, code samples, and inspiration to build communications and digital engagement experiences.