Console Application DI Pattern
A guide for implementing dependency injection using GenericHost in .NET Console Application.
- Required NuGet Package
<ItemGroup> <PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.*" /> </ItemGroup>
- Basic Implementation
2.1 Program.cs
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting;
var host = Host.CreateDefaultBuilder(args) .ConfigureServices((context, services) => { services.AddSingleton<IMyService, MyService>(); services.AddSingleton<App>(); }) .Build();
var app = host.Services.GetRequiredService<App>(); await app.RunAsync();
2.2 App.cs
namespace MyApp;
public sealed class App(IMyService myService) { private readonly IMyService _myService = myService;
public async Task RunAsync()
{
await _myService.DoWorkAsync();
}
}
- Service Lifetime
Lifetime Description Use When
Singleton
Single instance for entire app Stateless services
Scoped
Single instance per request DbContext
Transient
New instance per injection Lightweight services
- Configuration Integration
var host = Host.CreateDefaultBuilder(args) .ConfigureAppConfiguration((context, config) => { config.AddJsonFile("appsettings.json", optional: true); }) .ConfigureServices((context, services) => { services.Configure<AppSettings>( context.Configuration.GetSection("AppSettings")); services.AddSingleton<App>(); }) .Build();
- Logging Integration
public sealed class App(ILogger<App> logger) { public Task RunAsync() { logger.LogInformation("Application started"); return Task.CompletedTask; } }
- Important Notes
⚠️ Avoid Service Locator Pattern
// ❌ Bad example public sealed class BadService(IServiceProvider provider) { public void DoWork() { var service = provider.GetRequiredService<IMyService>(); } }
// ✅ Good example public sealed class GoodService(IMyService myService) { public void DoWork() { } }
⚠️ Captive Dependency
- Singleton should not inject Scoped/Transient dependencies
- References
- .NET Generic Host