3 Dependency Injection Mistakes I Made in ASP.NET Core Projects
Lessons learned from building and scaling ASP.NET Core applications

When I first started building ASP.NET Core applications, Dependency Injection (DI) felt like magic.
Register a service, inject it into a constructor, and everything just worked.
As my applications grew from small APIs to large enterprise systems, I learned that DI is easy to use but surprisingly easy to misuse.
Looking back at several production projects, there are three mistakes that caused me the most pain. If you're working with ASP.NET Core, avoiding these mistakes can save you hours of debugging and performance tuning.
Mistake #1: Treating Every Service as Transient
Early in my career, I had a simple rule:
builder.Services.AddTransient<IEmailService, EmailService>();
builder.Services.AddTransient<IReportService, ReportService>();
builder.Services.AddTransient<IUserService, UserService>();
When in doubt, I chose Transient.
It seemed harmless. After all, a new instance would be created every time it was needed.
The problem appeared when some services became more complex.
A service that loaded configuration, initialized expensive resources, or built large object graphs was suddenly being created dozens of times during a single request.
The application worked correctly, but unnecessary object creation increased memory allocations and made troubleshooting harder.
What I learned
The lifetime should match the behavior of the service.
Singleton for shared, stateless services.
Scoped for request-based operations.
Transient for lightweight services that truly need a new instance each time.
Choosing the correct lifetime is not about making the code compile. It's about matching the lifetime of the object to the problem you're solving.
Mistake #2: Putting Request-Specific Data Inside a Singleton
This was one of the most dangerous mistakes I made.
I created a singleton service to cache information that was expensive to retrieve.
builder.Services.AddSingleton<UserContext>();
Then I started storing user-related information inside it.
public class UserContext
{
public string CurrentUser { get; set; }
}
Everything worked perfectly during local testing.
Then multiple users started using the application.
Suddenly one user's information appeared in another user's workflow.
That was the day I truly understood what a Singleton means.
A singleton is shared across the entire application lifetime.
If multiple requests access the same object simultaneously, every piece of mutable state becomes a potential bug.
What I learned
Whenever I create a singleton today, I ask myself:
"Would I be comfortable if every user in the application touched this object at the same time?"
If the answer is no, it should not be a singleton.
Mistake #3: Building a 'God Service'
Dependency Injection makes adding dependencies extremely easy.
Too easy.
I once inherited a service constructor that looked something like this:
public OrderProcessor(
ILogger<OrderProcessor> logger,
IEmailService emailService,
IInventoryService inventoryService,
IUserService userService,
IReportService reportService,
IAuditService auditService,
INotificationService notificationService,
IConfiguration configuration)
{
}
The service had become responsible for everything.
The code technically worked, but it became difficult to test, difficult to maintain, and difficult to understand.
Every new feature resulted in another dependency being injected.
The real problem wasn't Dependency Injection.
The real problem was poor design.
A large number of dependencies is often a warning sign that a class has too many responsibilities.
What I learned
When a constructor starts growing uncontrollably, I stop and ask:
Is this class doing too much?
Can responsibilities be split into smaller services?
Can a workflow be broken into separate components?
Dependency Injection should reveal design problems, not hide them.
Final Thoughts
Dependency Injection is one of the best features of ASP.NET Core.
It helps create loosely coupled, testable, and maintainable applications.
But after years of building enterprise systems, I've learned that most DI problems aren't caused by the container itself.
They're caused by design decisions.
The three lessons that changed how I use DI are simple:
Don't default everything to
Transient.Never store request-specific state in
Singletonservices.When constructor parameters keep growing, rethink the design.
Dependency Injection is not just about registering services.
It's about managing object lifetimes and responsibilities correctly.
Get those two things right, and your applications become much easier to scale, test, and maintain.
What Dependency Injection mistake taught you the biggest lesson in your ASP.NET Core journey?
