Click here to Skip to main content
15,936,362 members
Articles / Programming Languages / C#

Effortlessly Resolving Circular Dependencies in .NET with SmartInject

Rate me:
Please Sign up or sign in to vote.
3.86/5 (4 votes)
3 Oct 2023CPOL2 min read 10.3K   6   2
Simplify and resolve circular dependencies in .NET using the SmartInject NuGet package
Handling circular dependencies in .NET can often be challenging and may lead to a cumbersome refactoring process. SmartInject is a versatile NuGet package designed to simplify this task, allowing developers to effortlessly manage and resolve circular dependencies through lazy loading. This article provides an insightful overview of how SmartInject operates, offering a practical solution to a common problem, without the need for extensive code restructuring.


Dependency Injection (DI) is a common technique to achieve Inversion of Control (IoC) between classes and their dependencies. However, developers may encounter a System.InvalidOperationException related to circular dependencies. This article introduces a convenient solution: SmartInject, a NuGet package that simplifies dependency injection in .NET by employing lazy loading to handle circular dependencies. Check it out on NuGet.


When dealing with classes that depend on each other, a circular dependency is created, leading to an infinite loop during object instantiation. This scenario typically requires refactoring to resolve, but SmartInject provides an efficient workaround by implementing lazy loading. With SmartInject, dependencies are resolved in a deferred manner, eliminating the circular dependency issue without the need for major code restructuring.

Using the Code

Consider a scenario where Something depends on SomethingElse, and vice versa:

public class Something
    public Something(SomethingElse somethingElse) { /*...*/ }

public class SomethingElse
    public SomethingElse(Something something) { /*...*/ }

This typical arrangement would throw a System.InvalidOperationException due to a circular dependency. With SmartInject, you can restructure the code as follows:

public class Something : ISomething
    private readonly Lazy<ISomethingElse> _somethingElse;
    public Something(Lazy<ISomethingElse> somethingElse)
        _somethingElse = somethingElse;

public class SomethingElse : ISomethingElse
    private readonly Lazy<ISomething> _something;
    public SomethingElse(Lazy<ISomething> something)
        _something = something;

With the Lazy<T> class, SmartInject ensures that instances are not created until they are needed, effectively breaking the circular dependency loop. Services can be registered using SmartInject’s specialized methods:

builder.Services.AddLazySingleton<ISomething, Something>();

SmartInject also supports other service lifetimes, providing flexibility for various application needs. You can choose from the following registration methods, based on your requirements:

// For singleton lifetime
builder.Services.AddLazySingleton<ISomething, Something>();

// For transient lifetime
builder.Services.AddLazyTransient<ISomething, Something>();

// For scoped lifetime
builder.Services.AddLazyScoped<ISomething, Something>();

Each method corresponds to a different service lifetime, allowing you to select the most appropriate one for your application's architecture and performance needs. For additional details, explore the SmartInject source code on GitHub.

Points of Interest

The SmartInject package offers an elegant solution to handle circular dependencies without requiring significant code restructuring. It introduces a deferred instantiation approach, improving the application's startup performance while integrating seamlessly with the .NET DI framework.


  • 3rd October, 2023: This is the initial publication of this trick. Future updates and improvements to the SmartInject package or related tricks will be documented in subsequent revisions.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Written By
Software Developer (Senior)
Netherlands Netherlands
I am a self-employed software engineer working on .NET Core. I love TDD.

Comments and Discussions

AnswerIsn't it an advertisement? Pin
Sergey Alexandrovich Kryukov3-Oct-23 12:08
mvaSergey Alexandrovich Kryukov3-Oct-23 12:08 
Isn't it an advertisement?

Please correct me if I'm wrong.

Not trying to depreciate the value of this product, I must say: you are suggesting downloading and using yet another software package, making the development only heavier, instead of promoting the culture of structuring the solutions in a well-maintainable manner, and that also includes the ability to perform deep refactoring.

I maintain that the problem of circular dependency does not exist! What does exist is a bad attitude and bad practices in solution structures. Should you get rid of bad practices, your solution will be maintained well at all stages and withstand even the trickiest turns due to new ideas and goals, no matter how big the solution is.

Thank you.
Sergey A Kryukov

GeneralRe: Isn't it an advertisement? Pin
Daan Acohen3-Oct-23 22:30
Daan Acohen3-Oct-23 22:30 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.