Dependency Injection (DI) is a key design principle that enhances modularity and testability by decoupling class dependencies. While third-party DI frameworks like Autofac offer extensive features, the DI container built into .NET Core (and later versions) provides a simple, performant, and tightly integrated solution. In this blog post, we’ll create a sample airline booking application using .NET’s built-in DI capabilities. We’ll explore its benefits, limitations, and compare it to Autofac.

Why Use .NET’s Built-in DI?

.NET’s built-in DI container is:

  • Lightweight: Optimized for performance and simplicity.
  • Integrated: Seamlessly works with ASP.NET Core, console applications, and other .NET project types.
  • Extensible: Supports common DI patterns and can integrate with third-party frameworks when necessary.

Sample Airline Application: Requirements

We’ll build a simplified airline booking application with the following services:

  1. FlightSearchService: Searches for available flights.
  2. BookingService: Handles flight bookings.
  3. PaymentProcessor: Processes payments.
  4. NotificationService: Sends notifications to customers.

Step-by-Step Implementation

Step 1: Define Interfaces and Implementations

Create interfaces and corresponding implementations for the services.

FlightSearchService

public interface IFlightSearchService
{
    IEnumerable<Flight> SearchFlights(string origin, string destination, DateTime travelDate);
}

public class FlightSearchService : IFlightSearchService
{
    public IEnumerable<Flight> SearchFlights(string origin, string destination, DateTime travelDate)
    {
        return new List<Flight>
        {
            new Flight { FlightNumber = "AI123", Origin = origin, Destination = destination, TravelDate = travelDate }
        };
    }
}

BookingService

public interface IBookingService
{
    Booking CreateBooking(Flight flight, Passenger passenger);
}

public class BookingService : IBookingService
{
    public Booking CreateBooking(Flight flight, Passenger passenger)
    {
        return new Booking { Flight = flight, Passenger = passenger, BookingId = Guid.NewGuid() };
    }
}

PaymentProcessor

public interface IPaymentProcessor
{
    bool ProcessPayment(string cardNumber, decimal amount);
}

public class PaymentProcessor : IPaymentProcessor
{
    public bool ProcessPayment(string cardNumber, decimal amount)
    {
        return true; // Simulate payment success
    }
}

NotificationService

public interface INotificationService
{
    void SendNotification(string email, string message);
}

public class NotificationService : INotificationService
{
    public void SendNotification(string email, string message)
    {
        Console.WriteLine($"Email sent to {email}: {message}");
    }
}

Step 2: Configure Services in .NET’s DI Container

In the Program.cs file (or Startup.cs in older versions), register the services with the DI container.

var builder = WebApplication.CreateBuilder(args);

// Register services
builder.Services.AddTransient<IFlightSearchService, FlightSearchService>();
builder.Services.AddTransient<IBookingService, BookingService>();
builder.Services.AddSingleton<IPaymentProcessor, PaymentProcessor>();
builder.Services.AddScoped<INotificationService, NotificationService>();

var app = builder.Build();

app.MapControllers();
app.Run();

Step 3: Inject Dependencies into Controllers

Use constructor injection to access the services in your controllers.

[ApiController]
[Route("api/[controller]")]
public class BookingController : ControllerBase
{
    private readonly IFlightSearchService _flightSearchService;
    private readonly IBookingService _bookingService;
    private readonly IPaymentProcessor _paymentProcessor;
    private readonly INotificationService _notificationService;

    public BookingController(
        IFlightSearchService flightSearchService,
        IBookingService bookingService,
        IPaymentProcessor paymentProcessor,
        INotificationService notificationService)
    {
        _flightSearchService = flightSearchService;
        _bookingService = bookingService;
        _paymentProcessor = paymentProcessor;
        _notificationService = notificationService;
    }

    [HttpPost("book")]
    public IActionResult BookFlight(BookingRequest request)
    {
        var flights = _flightSearchService.SearchFlights(request.Origin, request.Destination, request.TravelDate);
        var selectedFlight = flights.FirstOrDefault();
        if (selectedFlight == null) return NotFound("Flight not found.");

        var booking = _bookingService.CreateBooking(selectedFlight, request.Passenger);
        if (!_paymentProcessor.ProcessPayment(request.PaymentDetails.CardNumber, selectedFlight.Price))
            return BadRequest("Payment failed.");

        _notificationService.SendNotification(request.Passenger.Email, "Booking confirmed!");

        return Ok(booking);
    }
}

Comparing .NET DI to Autofac

Feature.NET DIAutofac
IntegrationBuilt into .NET CoreRequires additional setup
Ease of UseSimple and minimalisticMore complex but feature-rich
Advanced FeaturesLimitedSupports interceptors, decorators
Lifetime ScopesBasic (Transient, Scoped, Singleton)Highly customizable
PerformanceLightweight and fastSlightly more overhead
Community SupportOfficial Microsoft supportLarge open-source community

Summary

Using the built-in DI container in .NET is a practical choice for most applications, offering simplicity, tight integration, and excellent performance. For our airline booking application, it was straightforward to configure and use the required services.

However, if your application requires advanced DI features like decorators, interceptors, or dynamic module loading, Autofac might be a better fit. Each tool has its strengths and trade-offs, so the choice depends on your project’s complexity and specific needs.

By leveraging .NET’s DI or Autofac appropriately, you can create clean, maintainable, and testable code, ensuring a solid foundation for your application’s success.

Implementing Dependency Injection in .NET: Building a Sample Airline Application

Johannes Rest


.NET Architekt und Entwickler


Beitragsnavigation


Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert