Skip to content

Bits of .NET

Daily micro-tips for C#, SQL, performance, and scalable backend engineering.

  • Asp.Net Core
  • C#
  • SQL
  • JavaScript
  • CSS
  • About
  • ErcanOPAK.com
  • No Access
  • Privacy Policy
Asp.Net Core

Options Pattern in ASP.NET Core: Configuration Magic for Robust Apps

- 22.08.26 | 22.08.26 - ErcanOPAK

๐ŸŽฏ Key Takeaways: Clean, type-safe configuration binding with validation, reloading, and dependency injection. The definitive guide to IOptions, IOptionsSnapshot, and IOptionsMonitor.

Using strings and magic values in your code? The Options Pattern brings type-safety and flexibility to your configuration.

๐Ÿ“ฆ Basic Setup

// appsettings.json
{
  "EmailSettings": {
    "SmtpServer": "smtp.gmail.com",
    "SmtpPort": 587,
    "SenderEmail": "noreply@myapp.com",
    "SenderName": "MyApp",
    "EnableSsl": true,
    "MaxRetries": 3
  }
}

// Model
public class EmailSettings
{
    public string SmtpServer { get; set; } = string.Empty;
    public int SmtpPort { get; set; }
    public string SenderEmail { get; set; } = string.Empty;
    public string SenderName { get; set; } = string.Empty;
    public bool EnableSsl { get; set; }
    public int MaxRetries { get; set; }
}

// Registration
builder.Services.Configure<EmailSettings>(
    builder.Configuration.GetSection("EmailSettings"));

๐Ÿ”„ Three Options Types

// 1. IOptions<T> - Singleton (static after startup)
public class EmailService
{
    private readonly EmailSettings _settings;
    public EmailService(IOptions<EmailSettings> options)
    {
        _settings = options.Value; // โœ… Single snapshot
    }
}

// 2. IOptionsSnapshot<T> - Scoped (reloads on change)
public class EmailService
{
    private readonly IOptionsSnapshot<EmailSettings> _options;
    public EmailService(IOptionsSnapshot<EmailSettings> options)
    {
        _options = options; // โœ… Fresh each time
    }
    public void SendEmail()
    {
        var settings = _options.Value; // โœ… Reloaded per request
    }
}

// 3. IOptionsMonitor<T> - Singleton (auto-reloads, change notifications)
public class EmailService
{
    private readonly IOptionsMonitor<EmailSettings> _monitor;
    private readonly IDisposable? _changeListener;
    
    public EmailService(IOptionsMonitor<EmailSettings> monitor)
    {
        _monitor = monitor;
        _changeListener = _monitor.OnChange(settings =>
        {
            Console.WriteLine("Email config changed!");
            // React to changes
        });
    }
}

โœ… Validation

// With validation
public class EmailSettings
{
    [Required]
    [MinLength(5)]
    public string SmtpServer { get; set; } = string.Empty;
[Range(1, 65535)]
public int SmtpPort { get; set; }

[EmailAddress]
public string SenderEmail { get; set; } = string.Empty;

[Required]
public string SenderName { get; set; } = string.Empty;

[Range(1, 10)]
public int MaxRetries { get; set; }
}

// Validate on startup
builder.Services.AddOptions<EmailSettings>()
.Bind(builder.Configuration.GetSection("EmailSettings"))
.ValidateDataAnnotations()
.Validate(settings => settings.SmtpPort != 25, "SmtpPort cannot be 25(unsecure)")
.ValidateOnStart();

// ๐Ÿ”ฅ Throws exception if config is invalid!

๐Ÿ’ก Pro Tip: Environment – Specific Config

// appsettings.Development.json
{
"EmailSettings": {
"SmtpServer": "localhost",
"SmtpPort": 1025,
"MaxRetries": 1
}
}

// appsettings.Production.json
{
"EmailSettings": {
"SmtpServer": "smtp.sendgrid.net",
"SmtpPort": 587,
"MaxRetries": 5
}
}

// ๐Ÿ’ก Automatic based on ASPNETCORE_ENVIRONMENT

Related posts:

ASP.NET Core: Stop appsettings.json Secrets From Leaking Into Your Git History

Every Async Method Should Accept CancellationToken

.NET Core โ€œKestrel Timeoutโ€ โ€” The Hidden Request Body Limit

Post Views: 4

Post navigation

AsyncLocal and CallContext in C#: Mastering Async Flow State Management
SQL Window Functions: Revolutionizing Reporting Without Subqueries

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

October 2026
M T W T F S S
 1234
567891011
12131415161718
19202122232425
262728293031  
« Sep    

Most Viewed Posts

  • Get the User Name and Domain Name from an Email Address in SQL (973)
  • How to make theater mode the default for Youtube (952)
  • How to add default value for Entity Framework migrations for DateTime and Bool (939)
  • Get the First and Last Word from a String or Sentence in SQL (847)
  • How to select distinct rows in a datatable in C# (837)
  • How to enable, disable and check if Service Broker is enabled on a database in SQL Server (624)
  • Add Constraint to SQL Table to ensure email contains @ (590)
  • Average of all values in a column that are not zero in SQL (553)
  • How to use Map Mode for Vertical Scroll Mode in Visual Studio (526)
  • Find numbers with more than two decimal places in SQL (468)

Recent Posts

  • CSS: Fix a prefers-color-scheme Media Query That Gets Silently Overridden by a Browser Extension’s Forced Dark Mode
  • Git: Fix a Merge Commit That Silently Drops a File Because Both Branches Deleted It Differently
  • HTML5: Fix a Native Lazy-Loading Image That Never Loads Because It Sits Inside a Hidden Tab Until the User Clicks It
  • The AI Prompt That Traces a Null Reference Exception Back to the Exact Line That First Produced the Null
  • The AI Prompt That Turns a Gym Membership Contract’s Fine Print Into a Plain-English List of Cancellation Steps
  • Photoshop: Fix a Color Profile Mismatch That Makes Printed Output Look Nothing Like What You Saw On Screen
  • WordPress: Fix Search Results That Return Pages From a Theme You Deactivated Months Ago
  • Visual Studio: Fix a Test Project That Builds Fine Alone but Fails to Discover Any Tests After a NuGet Restore
  • ASP.NET Core: Fix a File Upload That Times Out on Slow Connections Only Because Kestrel’s Minimum Data Rate Feature Kicked In
  • JavaScript: Fix an Array Destructuring Default Value That Silently Never Applies Because null Was Passed Instead of Undefined

Most Viewed Posts

  • Get the User Name and Domain Name from an Email Address in SQL (973)
  • How to make theater mode the default for Youtube (952)
  • How to add default value for Entity Framework migrations for DateTime and Bool (939)
  • Get the First and Last Word from a String or Sentence in SQL (847)
  • How to select distinct rows in a datatable in C# (837)

Recent Posts

  • CSS: Fix a prefers-color-scheme Media Query That Gets Silently Overridden by a Browser Extension’s Forced Dark Mode
  • Git: Fix a Merge Commit That Silently Drops a File Because Both Branches Deleted It Differently
  • HTML5: Fix a Native Lazy-Loading Image That Never Loads Because It Sits Inside a Hidden Tab Until the User Clicks It
  • The AI Prompt That Traces a Null Reference Exception Back to the Exact Line That First Produced the Null
  • The AI Prompt That Turns a Gym Membership Contract’s Fine Print Into a Plain-English List of Cancellation Steps

Social

  • ErcanOPAK.com
  • GoodReads
  • LetterBoxD
  • Linkedin
  • The Blog
  • Twitter
© 2026 Bits of .NET | Built with Xblog Plus free WordPress theme by wpthemespace.com