Introduction
The Singleton pattern ensures that a class has only one instance throughout an application and provides a single, globally accessible way to retrieve it.
Learn through examples of common use cases with several code samples.
All code was written in Microsoft Visual Studio 2026.
Advantages: A Singleton provides controlled access to a shared resource, avoids the overhead and inconsistency of creating multiple instances, and can centralize application-wide services such as configuration, logging, or caching. When implemented carefully, it also supports lazy initialization, so the instance is created only when first requested.
Key Implementation Rules
To successfully build a singleton, you need to enforce two core rules:
- sealed class modifier: Prevents subclassing, which could otherwise result in multiple unique instances of the derived classes.
- private parameterless constructor: Prevents external code from creating new instances using the new keyword.
Main Source code Library Source code Test Source code
Example 1
Provides a list of month names and indices useful in a web project dropdown element for add and edit pages.
using SingletonsApp.Models;
using static System.Globalization.DateTimeFormatInfo;
namespace SingletonsApp.Classes.SingletonSamples;
public sealed class Basic1
{
private static readonly Lazy<Basic1> Lazy = new(() => new Basic1());
public static Basic1 Instance => Lazy.Value;
public List<MonthItem> MonthList =>
[
.. CurrentInfo.MonthNames[..^1]
.Select((monthName, index) =>
new MonthItem(index + 1, monthName))
];
}
Enter fullscreen mode Exit fullscreen mode
💡 Using Lazy handles thread safety and lazy initialization automatically behind the scenes
ASP.NET Core example
Creates a dropdown using Helpers.Instance.MonthList same as above with a different class name.
@page
@model IndexModel
@{
ViewData["Title"] = "Month Selection";
}
<div class="container mt-5">
<div class="d-flex justify-content-center">
<form method="post">
<div class="mb-3">
<label asp-for="SelectedMonth" class="form-label">
Select month
</label>
<select asp-for="SelectedMonth"
class="form-select"
style="width: 250px;">
<option value="">Select a month</option>
@foreach (var month in Model.MonthItems)
{
<option value="@month.Index">
@month.Name
</option>
}
</select>
</div>
<button type="submit"
class="btn btn-primary">
Get Month
</button>
@if (Model.SelectedMonthItem is not null)
{
<div class="alert alert-success mt-3">
Selected month:
<strong>@Model.SelectedMonthItem.Name</strong>
(@Model.SelectedMonthItem.Index)
</div>
}
</form>
</div>
</div>
Enter fullscreen mode Exit fullscreen mode
Backend
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using SingletonWebApp.Classes;
using SingletonWebApp.Models;
namespace SingletonWebApp.Pages;
public class IndexModel : PageModel
{
public List<MonthItem> MonthItems { get; set; } = [];
[BindProperty]
public int? SelectedMonth { get; set; }
public MonthItem? SelectedMonthItem { get; set; }
public void OnGet()
{
MonthItems = Helpers.Instance.MonthList;
}
public void OnPost()
{
MonthItems = Helpers.Instance.MonthList;
SelectedMonthItem = MonthItems
.FirstOrDefault(month => month.Index == SelectedMonth);
}
}
Enter fullscreen mode Exit fullscreen mode
Do the same for Helpers.Instance.MonthList in other pages.
Dependency Injection version
using static System.Globalization.DateTimeFormatInfo;
using SingletonWebApp.Models;
namespace SingletonWebApp.Classes;
public sealed class Helpers
{
//private static readonly Lazy<Helpers> Lazy = new(() => new Helpers());
//public static Helpers Instance => Lazy.Value;
public List<MonthItem> MonthList { get; init; }
public Helpers()
{
MonthList = CurrentInfo.MonthNames[..^1]
.Select((monthName, index) =>
new MonthItem(index + 1, monthName)).ToList();
}
}
Enter fullscreen mode Exit fullscreen mode
💡 Here we need a public constructor
Program.cs register Helpers class.
public class Program
{
public static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorPages();
// Register Helpers as a singleton
builder.Services.AddSingleton<Helpers>();
Enter fullscreen mode Exit fullscreen mode
Index.cshtml.cs
💡 note use of primary constructor
public class IndexModel(Helpers helpers) : PageModel
{
public List<MonthItem> MonthItems { get; set; } = [];
[BindProperty]
public int? SelectedMonth { get; set; }
public MonthItem? SelectedMonthItem { get; set; }
private readonly Helpers _helpers = helpers;
public void OnGet()
{
MonthItems = _helpers.MonthList;
}
public void OnPost()
{
MonthItems = _helpers.MonthList;
SelectedMonthItem = MonthItems
.FirstOrDefault(month => month.Index == SelectedMonth);
}
}
Enter fullscreen mode Exit fullscreen mode
Example 2
This example was originally done with a database and no singleton.
"TransactionInformation": {
"CurrentValue": "MW00001"
}
Enter fullscreen mode Exit fullscreen mode
Each time a waiter takes a order for a table CurrentValue is incremented by 1 and updates the value in appsettings.json
public sealed class Basic2
{
private static readonly Lazy<Basic2> Lazy = new(() => new Basic2());
public static Basic2 Instance => Lazy.Value;
public TransactionInformation Transaction { get; set; }
public void UpdateTransactionIdentifier()
{
TransactionInformationReader.Save(Transaction);
}
private Basic2()
{
TransactionInformation? x = TransactionInformationReader.Load();
Transaction = new TransactionInformation()
{
CurrentValue = x.CurrentValue
};
}
}
Enter fullscreen mode Exit fullscreen mode
Example 3
Uses IHostEnvironment Interface to determine if the current application is in development, staging or production environment and sets the application database connection.
using Microsoft.Extensions.Hosting;
using SingletonsApp.Models;
namespace SingletonsApp.Classes.Configuration;
public static class HostEnvironmentExtensions
{
extension(IHostEnvironment environment)
{
public bool CheckIsDevelopmentEnvironment() => environment.IsDevelopment();
public bool CheckIsStagingEnvironment() => environment.IsStaging();
public bool CheckIsProductionEnvironment() => environment.IsProduction();
public void DebugPrint(string databaseConnectionString, HelpDesk helpDesk)
{
if (environment.IsProduction()) return;
Console.WriteLine($" Current Environment: {environment.EnvironmentName}");
Console.WriteLine($" Application Name: {environment.ApplicationName}");
Console.WriteLine($" Content Root Path: {environment.ContentRootPath}");
Console.WriteLine($"Database Connection String: {databaseConnectionString}");
Console.WriteLine($" Help Desk Phone: {helpDesk.Phone}");
Console.WriteLine($" Help Desk Email: {helpDesk.Email}");
}
}
}
Enter fullscreen mode Exit fullscreen mode
Singleton
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using SingletonsApp.Classes.Configuration;
using SingletonsApp.Models;
namespace SingletonsApp.Singletons;
public sealed class EnvironmentSettings
{
private static readonly Lazy<EnvironmentSettings> Lazy = new(() => new EnvironmentSettings());
public static EnvironmentSettings Instance => Lazy.Value;
public AppEnvironment Environment { get; init; }
public HelpDesk HelpDesk { get; init; }
public string DatabaseConnectionString { get; init; } = null!;
private EnvironmentSettings()
{
DataConnections connections = AppSettingsReader.LoadConnectionStringsConnections();
HelpDesk = AppSettingsReader.LoadHelpDesk();
using IHost host = Host.CreateDefaultBuilder().Build();
IHostEnvironment environment = host.Services.GetRequiredService<IHostEnvironment>();
if (environment.CheckIsDevelopmentEnvironment())
{
Environment = AppEnvironment.Development;
DatabaseConnectionString = connections.ConnectionStrings.DevelopmentConnection;
}
if (environment.CheckIsStagingEnvironment())
{
Environment = AppEnvironment.Staging;
DatabaseConnectionString = connections.ConnectionStrings.StagingConnection;
}
if (environment.CheckIsProductionEnvironment())
{
Environment = AppEnvironment.Production;
DatabaseConnectionString = connections.ConnectionStrings.ProductionConnection;
}
}
}
Enter fullscreen mode Exit fullscreen mode

