How to implement dependency injection in Startup.cs when dependencies are circular?
Asked Answered
A

2

9

I have a MyProject project where I have IMyService interface and MyService class that implements IMyService. In Startup.cs class I dependency injection them:

// MyProject project | Startup.cs
public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<IMyService, MyService>();
}

Because MyService has many dependencies (makes many REST calls to 3rd party etc.) I would like to create a stub version of it for development environment. I created new MyStubsProject that references to MyProject. And I implemented stub version of IMyService to MyStubsProject:

// MyStubsProject project
public class MyStubService : IMyService
{
    ...
}

So now I want to add dependency injection to Startup.cs class:

// MyProject project | Startup.cs
public void ConfigureServices(IServiceCollection services)
{
    if (isDevelopmentEnvironment)
        services.AddScoped<IMyService, MyStubService>();
    else
        services.AddScoped<IMyService, MyService>();
}

But if I add that, there will be circular dependency between MyProject and MyStubsProject.

How should I implement reference to the class MyStubService or MyStubsProject project in Startup.cs?

Artificiality answered 14/12, 2018 at 13:11 Comment(0)
C
7

The best answer is probably to extract your service stuff into a separate project, or at least the service contracts (IMyService). That should let both of your existing projects reference the service contracts without any conflicts. If you want to add other interfaces or add more implementations of the same interface, this will now be easy too.

An additional benefit may be a better overall architecture: Keeping contracts in a separate project without any actual logic (only interfaces) will generally result in better organized and cleaner code.

Coessential answered 14/12, 2018 at 13:20 Comment(1)
But there is a one problem: IMyService is a big one with references to other projects. I would like if there is an answer where I don’t have to make any changes to it. But clearly in the long run splitting IMyService and moving it to own project is the best solution.Artificiality
P
1

You can use the precompiler directive #if to determine if your project is set to debug or release. The compiler will do the rest!

// MyProject project | Startup.cs
public void ConfigureServices(IServiceCollection services)
{
#IF DEBUG
        services.AddScoped<IMyService, MyStubService>();
#ELSE
        services.AddScoped<IMyService, MyService>();
#ENDIF
}
Parallax answered 14/12, 2018 at 13:20 Comment(2)
Will this work though? Won't you at least have to add precompiler directives to toggle which using-statements to apply too?Coessential
You shouldn't have to do anything additional. The compiler will strip out any unused #using lines that you may have.Parallax

© 2022 - 2024 — McMap. All rights reserved.