Dependency Injection (DI) is a design pattern that allows us to achieve Inversion of Control (IoC) by injecting dependencies into a class rather than instantiating them within the class itself. Autofac is one of the most popular DI frameworks for .NET, offering robust and flexible dependency management. In this blog post, we’ll explore how to use Autofac in a sample airline booking application, discussing its benefits, limitations, and implementation details.

Why Autofac?

Autofac is favored for its ease of use, flexibility, and powerful features. Key benefits include:

  • Module-based Registration: Simplifies complex applications by grouping dependencies logically.
  • Lifetime Management: Offers various lifetime scopes for objects, such as singleton, transient, or per-request.
  • Integration with .NET: Seamlessly integrates with ASP.NET Core, WPF, and other .NET frameworks.
  • Advanced Features: Supports generics, decorators, interceptors, and more.

Sample Airline Application: Requirements

Let’s consider a simplified airline booking application. The application has the following components:

  1. FlightSearchService: Fetches available flights based on user input.
  2. BookingService: Manages booking reservations.
  3. PaymentProcessor: Handles payment processing.
  4. NotificationService: Sends email notifications to customers.

We’ll use Autofac to wire up these services in a way that adheres to the principles of DI.


Step-by-Step Implementation

Step 1: Install Autofac

First, add the Autofac NuGet package to your project. For ASP.NET Core applications, you’ll also need the Autofac.Extensions.DependencyInjection package.

Install-Package Autofac
Install-Package Autofac.Extensions.DependencyInjection

Step 2: Define Interfaces and Implementations

Create interfaces for each service and their respective implementations:

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)
    {
        // Simulate a database query
        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 3: Register Services with Autofac

Create a new Autofac Module to manage your service registrations.

public class AirlineModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        builder.RegisterType<FlightSearchService>().As<IFlightSearchService>().InstancePerDependency();
        builder.RegisterType<BookingService>().As<IBookingService>().InstancePerDependency();
        builder.RegisterType<PaymentProcessor>().As<IPaymentProcessor>().SingleInstance();
        builder.RegisterType<NotificationService>().As<INotificationService>().InstancePerLifetimeScope();
    }
}

Step 4: Configure Autofac in ASP.NET Core

Modify the Program.cs file to use Autofac as the DI container.

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .UseServiceProviderFactory(new AutofacServiceProviderFactory())
        .ConfigureContainer<ContainerBuilder>(builder =>
        {
            builder.RegisterModule(new AirlineModule());
        })
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        });

Step 5: Use Dependency Injection in Controllers

Inject services into controllers to implement application logic.

[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);
    }
}

Pros of Using Autofac

  1. Modularity: Enables modular design with logical grouping of dependencies.
  2. Advanced Features: Supports advanced use cases such as interception, child containers, and circular dependencies.
  3. Flexibility: Provides fine-grained control over dependency lifetimes and scopes.
  4. Community Support: Well-documented and widely used, with an active community.

Cons of Using Autofac

  1. Overhead: May introduce performance overhead for large applications.
  2. Learning Curve: Some features require an in-depth understanding to use effectively.
  3. Redundancy: With the built-in DI in .NET Core, using Autofac might seem redundant for simple projects.

Summary

Autofac is a powerful DI framework that excels in handling complex dependency scenarios in .NET applications. In this blog post, we implemented a sample airline application using Autofac, showcasing its modularity, flexibility, and ease of integration. While it’s a robust tool for managing dependencies, careful consideration is needed to balance its benefits against potential overhead, especially for smaller projects.

With Autofac, your application can achieve clean, maintainable, and testable code, making it a great choice for developers seeking an advanced DI solution.

Implementing Dependency Injection with Autofac in 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