A direct dependency is an object or service that a component declares through its public constructor or method interface and receives from outside. The declaration makes the component’s requirements visible without inspecting its implementation. section 8.1
In C#, constructor parameters and endpoint-handler parameters are common ways to declare direct dependencies. A component can then use the supplied instance while leaving creation to another part of the application, commonly a dependency-injection container. section 8.6 section 8.1
Direct dependencies make code easier to reason about and change:
- They reveal what a class or handler needs through its interface. section 8.1
- They avoid embedding object construction inside business logic. section 8.1
- They allow the dependency provider to build the complete dependency graph and supply configured instances. section 8.6
- They contrast with implicit dependencies, which are hidden in implementation details and are harder to reason about and test. section 8.1
Email sending with a direct dependency
Instead of constructing EmailSender inside RegisterUser, declare it as a parameter: `string RegisterUser(string username, EmailSender emailSender)`. The handler calls `emailSender.SendEmail(username)`, while the container supplies EmailSender and its own dependencies, such as NetworkClient and MessageFactory. section 8.1 section 8.1
Listing 8.2 A service with multiple dependencies
public class EmailSender
{
private readonly NetworkClient _client; #1
private readonly MessageFactory _factory; #1
public EmailSender(MessageFactory factory, NetworkClient client) #2
{ #2
_factory = factory; #2
_client = client; #2
} #2
public void SendEmail(string username)
{
var email = _factory.Create(username); #3
_client.SendEmail(email); #3
Console.WriteLine($"Email sent to {username}!");
}
}
Inspect how a service declares multiple direct dependencies through its constructor. section 8.1
Listing 8.4 Sending an email using DI to inject dependencies
string RegisterUser(string username, EmailSender emailSender) #1
{
emailSender.SendEmail(username); #2
return $"Email sent to {username}!"; #2
}
Inspect the endpoint-handler signature that declares EmailSender as a direct dependency. section 8.1
