Sponsor: Using RabbitMQ or Azure Service Bus in your .NET systems? Well, you could just use their SDKs and roll your own serialization, routing, outbox, retries, and telemetry. I mean, seriously, how hard could it be?

Constructor & Setter Injection
Passing your dependencies via the constructor is generally a better way of injecting dependencies instead of setters. Constructor injection gives you a much clearer definition of what dependencies are needed in order to construct the object into a valid state. My dependencies fields are usually readonly, to prevent them from being externally set after object creation. Regardless if you use constructor or setter injection with your container of choice, there is often one injection method that is seemingly rarely used or mentioned. Pass your dependency to the method that requires it. How often have you seen a constructor take a pile of dependencies via it’s constructor, to which those dependencies were used in a limited amount of methods. I often see this when looking at CQRS Command Handlers.class InventoryHandler { private readonly IRepository _repository; private readonly IBus _bus; private readonly IValidateInventory _validation; public InventoryHandler(IRepository repository, IBus bus, IValidateInventory validation) { _repository = repository; _bus = bus _validation = validation; } public void Handle(ReceiveInventory cmd) { if (!_validation.IsAvailable(cmd.ProductId)) { throw new InvalidOperationException("Cannot receive inventory"); } // Receive Product into Inventory var inventory = _repository.GetById(cmd.ProductId); inventory.Receive(cmd.Quantity, cmd.UnitCost); } public Handle(RemoveInventory cmd) { // Remove product from inventory var inventory = _repository.GetById(cmd.ProductId); inventory.RemoveInventory(cmd.Quantity); // Pub/Sub to notify other bounded context of inventory removal _bus.Send(new InventoryRemovedMessage(cmd.InventoryId)); } }In this simplified example, IRepository is used in both Handle() methods. However, IBus & IValidateInventory are both only used in one method each. Instead of passing the dependencies via constructor, pass the required dependencies to the method that requires it.
class InventoryHandler { private readonly IRepository _repository; public InventoryHandler(IRepository repository) { _repository = repository; } public void Handle(IValidateInventory validation, ReceiveInventory cmd) { if (!validation.IsAvailable(cmd.ProductId)) { throw new InvalidOperationException("Cannot receive inventory"); } // Receive Product into Inventory var inventory = _repository.GetById(cmd.ProductId); inventory.Receive(cmd.Quantity, cmd.UnitCost); } public Handle(IBus bus, RemoveInventory cmd) { // Remove product from inventory var inventory = _repository.GetById(cmd.ProductId); inventory.RemoveInventory(cmd.Quantity); // Pub/Sub to notify other bounded context of inventory removal bus.Send(new InventoryRemovedMessage(cmd.InventoryId)); } }
Nested Dependencies
The primary reason why I prefer not to use a dependency injection container is because it potentially masks a code smell. Nested dependencies or over abstraction can add complexity by adding unnecessary layers. Have you seen something similar to this before?public class MyService(IRepository repostiory) { ... } public class Repository(IUnitOfWork unitOfWork) { ... } public class UnitOfWork(IDbContext dbContext) { ... } public class DbContext(IDbConnection dbConnection) { ... } public class DbConnection(string connectionString) { ... }
