A comprehensive tutorial project demonstrating Dependency Injection (DI) patterns in both .NET Core and .NET Framework. This project shows how to implement DI using two different approaches: Microsoft's built-in DI container and Autofac.
This project contains two implementations of the same weather forecasting application:
- DotNetCore - Uses Microsoft.Extensions.DependencyInjection (built-in DI)
- DotNetFramework - Uses Autofac (third-party DI container)
Both implementations demonstrate the same concept: decoupling services from their implementations through dependency injection.
Dependency Injection is a design pattern that promotes loose coupling and increases code maintainability by:
- Removing hard dependencies between classes
- Making code testable and mockable
- Following the Dependency Inversion Principle
- Improving code reusability
DependencyInjection/
βββ DotNetCore/
β βββ Program.cs # .NET Core implementation with built-in DI
β βββ DotNetCore.csproj # .NET Core project file (targets net10.0)
βββ DotNetFramework/
β βββ Program.cs # .NET Framework implementation with Autofac
β βββ App.config # Application configuration
β βββ DotNetFramework.csproj
β βββ packages.config # NuGet package references
βββ packages/ # External packages directory
βββ .gitignore # Git ignore rules
βββ DependencyInjection.slnx # Solution file
- .NET 10.0 SDK (for DotNetCore project)
- .NET Framework 4.x (for DotNetFramework project)
- Visual Studio 2022 or VS Code with C# extension
cd DotNetCore
dotnet runOutput:
The temprature in Pune is 32.5
cd DotNetFramework
dotnet runOutput:
The temprature in Pune is 32.5
using Microsoft.Extensions.DependencyInjection;
var serviceCollection = new ServiceCollection();
// Register service and its implementation as Transient
serviceCollection.AddTransient<IWhetherServiceClient, WhetherForcastClient>();
serviceCollection.AddTransient<WheatherForcastService>();
// Build the service provider
using(var service = serviceCollection.BuildServiceProvider())
{
var provider = service.GetRequiredService<WheatherForcastService>();
var temprature = provider.GetTemprature("Pune");
Console.WriteLine($"The temprature in Pune is {temprature}");
}interface IWhetherServiceClient
{
(string city, double temprature) GetCurrentWheatherReport(string city);
}class WhetherForcastClient : IWhetherServiceClient
{
public (string city, double temprature) GetCurrentWheatherReport(string city)
{
// Simulating a call to an external weather service
return (city, 32.5);
}
}class WheatherForcastService
{
private readonly IWhetherServiceClient _whetherServiceClient;
// Dependency is injected through constructor
public WheatherForcastService(IWhetherServiceClient whetherServiceClient)
{
_whetherServiceClient = whetherServiceClient;
}
public double GetTemprature(string city)
{
return _whetherServiceClient.GetCurrentWheatherReport(city).temprature;
}
}using Autofac;
using System;
// Create container builder
var builder = new ContainerBuilder();
// Register types
builder.RegisterType<WhetherForcastClient>().As<IWhetherServiceClient>();
builder.RegisterType<WheatherForcastService>();
// Build the container
using (var container = builder.Build())
{
// Resolve dependencies
var wheatherService = container.Resolve<WheatherForcastService>();
var temprature = wheatherService.GetTemprature("Pune");
Console.WriteLine($"The temprature in Pune is {temprature}");
}- Uses
ContainerBuilderinstead ofServiceCollection - Uses
Resolve<T>()instead ofGetRequiredService<T>() - More advanced features like modules, scanning, and interceptors
- Better support for property injection
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.1" />
</ItemGroup>Autofac (v9.0.0)
Autofac.Extensions.DependencyInjection (v10.0.0)
Microsoft.Extensions.DependencyInjection.Abstractions (v8.0.1)Both frameworks support different service lifetimes:
// Transient - New instance every time
serviceCollection.AddTransient<IService, Service>();
// Scoped - New instance per scope (common in web apps)
serviceCollection.AddScoped<IService, Service>();
// Singleton - Single instance for application lifetime
serviceCollection.AddSingleton<IService, Service>();// Transient (default)
builder.RegisterType<Service>().As<IService>();
// Instance per lifetime scope
builder.RegisterType<Service>().As<IService>().InstancePerLifetimeScope();
// Single instance
builder.RegisterType<Service>().As<IService>().SingleInstance();A major benefit of DI is easier unit testing. You can create mock implementations:
// Mock implementation for testing
class MockWhetherServiceClient : IWhetherServiceClient
{
public (string city, double temprature) GetCurrentWheatherReport(string city)
{
return (city, 25.0); // Fixed temperature for testing
}
}
// Use in tests
var mockClient = new MockWhetherServiceClient();
var service = new WheatherForcastService(mockClient);
var temp = service.GetTemprature("TestCity");
Assert.Equal(25.0, temp);# Build the project
Ctrl+Shift+B (or run: dotnet build)
# Publish the project
dotnet publish
# Watch for changes
dotnet watch run# DotNetCore
dotnet build DotNetCore/DotNetCore.csproj
dotnet publish DotNetCore/DotNetCore.csproj
# DotNetFramework
dotnet build DotNetFramework/DotNetFramework.csprojBy studying this project, you'll understand:
β
What Dependency Injection is and why it matters
β
How to use Microsoft's built-in DI container
β
How to use Autofac for advanced DI scenarios
β
Service registration and lifetime management
β
Constructor injection patterns
β
Loose coupling and SOLID principles
β
How to make code more testable
- Constructor Injection - Passing dependencies through constructor
- Service Locator Pattern - Anti-pattern; DI is preferred
- Factory Pattern - Alternative approach for object creation
- SOLID Principles - Dependency Inversion Principle especially relevant
- Microsoft.Extensions.DependencyInjection Documentation
- Autofac Documentation
- ASP.NET Core Dependency Injection
- SOLID Principles
- Both implementations achieve the same result using different DI containers
- The weather data is simulated and always returns 32.5Β°C
- This is a console application demonstrating core DI concepts
- For production scenarios, consider ASP.NET Core which has built-in DI support
Feel free to enhance this tutorial by:
- Adding more service examples
- Implementing different lifetime patterns
- Adding property injection examples
- Creating unit tests
- Adding error handling patterns
This project is licensed under the MIT License - see the LICENSE file for details.
The MIT License is a permissive open-source license that allows you to:
- β Use this project for commercial purposes
- β Modify the code
- β Distribute the software
- β Use it privately
The only requirement is to include a copy of the license and copyright notice.
Created by Subrata Mohanta
Connect with me on:
- π LinkedIn: linkedin.com/in/subratamohanta
- πΊ YouTube: @technicalodiyatoka
- π» GitHub: @subratamohanta
Feel free to reach out, ask questions, or share feedback about this project!
Last Updated: December 2025