Introduction
.NET Platform Extensions are a set of NuGet packages built on top of the .NET runtime that provide cross-cutting functionality not included in the base class libraries. They cover dependency injection, configuration, logging, hosting, HTTP client management, caching, and more. These packages follow the Microsoft.Extensions.* naming convention and are the foundation of ASP.NET Core's infrastructure, but they can be used in any .NET application — console apps, worker services, WPF, MAUI, and libraries. They are documented under the ".NET Platform Extensions" section on docs.microsoft.com.
Core Packages Overview
1// The most commonly used Microsoft.Extensions packages:
2
3// 1. Dependency Injection
4// Microsoft.Extensions.DependencyInjection
5services.AddSingleton<IMyService, MyService>();
6services.AddTransient<IRepository, SqlRepository>();
7
8// 2. Configuration
9// Microsoft.Extensions.Configuration
10var config = new ConfigurationBuilder()
11 .AddJsonFile("appsettings.json")
12 .AddEnvironmentVariables()
13 .Build();
14
15// 3. Logging
16// Microsoft.Extensions.Logging
17logger.LogInformation("Processing order {OrderId}", orderId);
18
19// 4. Options Pattern
20// Microsoft.Extensions.Options
21services.Configure<SmtpSettings>(config.GetSection("Smtp"));
22
23// 5. HTTP Client Factory
24// Microsoft.Extensions.Http
25services.AddHttpClient<GitHubClient>(client =>
26 client.BaseAddress = new Uri("https://api.github.com"));
27
28// 6. Hosting
29// Microsoft.Extensions.Hosting
30Host.CreateDefaultBuilder(args)
31 .ConfigureServices(services => services.AddHostedService<Worker>());
Dependency Injection
1using Microsoft.Extensions.DependencyInjection;
2
3// Register services
4var services = new ServiceCollection();
5services.AddSingleton<ICache, MemoryCache>();
6services.AddTransient<IOrderService, OrderService>();
7services.AddScoped<IDbContext, AppDbContext>();
8
9// Build the service provider
10var provider = services.BuildServiceProvider();
11
12// Resolve services
13var orderService = provider.GetRequiredService<IOrderService>();
14orderService.PlaceOrder(new Order { Id = 1 });
15
16// Lifetime scopes:
17// Singleton — one instance for the entire application
18// Scoped — one instance per scope (per HTTP request in ASP.NET)
19// Transient — new instance every time it's requested
The DI container is the backbone of .NET Platform Extensions. Most other extensions (logging, configuration, HTTP clients) integrate with it through IServiceCollection extension methods.
Configuration
1using Microsoft.Extensions.Configuration;
2
3// Build configuration from multiple sources
4IConfiguration config = new ConfigurationBuilder()
5 .SetBasePath(Directory.GetCurrentDirectory())
6 .AddJsonFile("appsettings.json", optional: false)
7 .AddJsonFile($"appsettings.{env}.json", optional: true)
8 .AddEnvironmentVariables()
9 .AddCommandLine(args)
10 .Build();
11
12// Read values
13string connString = config.GetConnectionString("DefaultConnection");
14int timeout = config.GetValue<int>("Settings:Timeout", defaultValue: 30);
15
16// Bind to a strongly-typed class
17var settings = new AppSettings();
18config.GetSection("App").Bind(settings);
19// Or with the Options pattern:
20services.Configure<AppSettings>(config.GetSection("App"));
Configuration sources are layered — later sources override earlier ones. Environment variables override JSON files, and command-line arguments override everything.
Logging
1using Microsoft.Extensions.Logging;
2
3// Setup logging
4var loggerFactory = LoggerFactory.Create(builder =>
5{
6 builder.AddConsole();
7 builder.AddDebug();
8 builder.SetMinimumLevel(LogLevel.Information);
9});
10
11ILogger logger = loggerFactory.CreateLogger<MyService>();
12
13// Structured logging with message templates
14logger.LogInformation("Order {OrderId} placed by {UserId}", 42, "alice");
15logger.LogWarning("Retry attempt {Attempt} of {MaxRetries}", 3, 5);
16logger.LogError(ex, "Failed to process order {OrderId}", 42);
17
18// Log levels: Trace < Debug < Information < Warning < Error < Critical
The logging abstraction supports structured logging with message templates (not string interpolation). Log providers (Console, Debug, Serilog, NLog, Application Insights) plug in without changing application code.
Hosting and Background Services
1using Microsoft.Extensions.Hosting;
2
3// Generic host for console apps and worker services
4var host = Host.CreateDefaultBuilder(args)
5 .ConfigureServices(services =>
6 {
7 services.AddHostedService<DataSyncWorker>();
8 })
9 .Build();
10
11await host.RunAsync();
12
13// Background service implementation
14public class DataSyncWorker : BackgroundService
15{
16 private readonly ILogger<DataSyncWorker> _logger;
17
18 public DataSyncWorker(ILogger<DataSyncWorker> logger) => _logger = logger;
19
20 protected override async Task ExecuteAsync(CancellationToken stoppingToken)
21 {
22 while (!stoppingToken.IsCancellationRequested)
23 {
24 _logger.LogInformation("Syncing data at {Time}", DateTime.UtcNow);
25 // Do work...
26 await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken);
27 }
28 }
29}
Host.CreateDefaultBuilder wires up configuration, logging, and DI automatically. BackgroundService provides a base class for long-running background tasks with graceful shutdown support.
HTTP Client Factory
1using Microsoft.Extensions.DependencyInjection;
2using Microsoft.Extensions.Http;
3
4// Register named HTTP clients
5services.AddHttpClient("github", client =>
6{
7 client.BaseAddress = new Uri("https://api.github.com/");
8 client.DefaultRequestHeaders.Add("User-Agent", "MyApp");
9});
10
11// Typed HTTP client
12services.AddHttpClient<GitHubService>(client =>
13{
14 client.BaseAddress = new Uri("https://api.github.com/");
15});
16
17// Usage via DI
18public class GitHubService
19{
20 private readonly HttpClient _client;
21
22 public GitHubService(HttpClient client) => _client = client;
23
24 public async Task<string> GetRepoAsync(string owner, string repo)
25 {
26 var response = await _client.GetStringAsync($"repos/{owner}/{repo}");
27 return response;
28 }
29}
IHttpClientFactory manages HttpClient lifetimes, preventing socket exhaustion from creating too many clients and DNS stale-cache issues from reusing a single client too long.
Common Pitfalls
Resolving scoped services from the root provider: Resolving a scoped service (like DbContext) from the root IServiceProvider instead of a scope creates a singleton instance that is never disposed, causing memory leaks and stale data. Always resolve scoped services within a using var scope = provider.CreateScope().
Capturing IServiceProvider in singletons: A singleton service that holds a reference to IServiceProvider and resolves scoped or transient services creates a "captive dependency" — scoped services become effectively singletons. Use IServiceScopeFactory instead.
Using string interpolation in log messages: logger.LogInformation($"Order {orderId}") creates a new string on every call, even when the log level is disabled. Use message templates: logger.LogInformation("Order {OrderId}", orderId) — the template is only formatted when the message is actually logged.
Not using IOptions<T> for configuration binding: Reading configuration values directly with config["Key"] throughout the codebase scatters magic strings everywhere. Use the Options pattern (IOptions<T>, IOptionsMonitor<T>) to bind configuration sections to strongly-typed classes and inject them via DI.
Creating HttpClient manually instead of using IHttpClientFactory: new HttpClient() in a using block causes socket exhaustion under load because sockets linger in TIME_WAIT state. IHttpClientFactory manages handler lifetimes and connection pooling automatically.
Summary
.NET Platform Extensions are Microsoft.Extensions.* NuGet packages providing DI, configuration, logging, hosting, and HTTP client management
They are the foundation of ASP.NET Core but work in any .NET application type
Use IServiceCollection to register services and IServiceProvider to resolve them
Configuration supports multiple layered sources (JSON, environment variables, command line)
Logging uses structured message templates — not string interpolation
IHttpClientFactory manages HTTP client lifetimes to prevent socket exhaustion