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:
- FlightSearchService: Fetches available flights based on user input.
- BookingService: Manages booking reservations.
- PaymentProcessor: Handles payment processing.
- 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
- Modularity: Enables modular design with logical grouping of dependencies.
- Advanced Features: Supports advanced use cases such as interception, child containers, and circular dependencies.
- Flexibility: Provides fine-grained control over dependency lifetimes and scopes.
- Community Support: Well-documented and widely used, with an active community.
Cons of Using Autofac
- Overhead: May introduce performance overhead for large applications.
- Learning Curve: Some features require an in-depth understanding to use effectively.
- 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.