简体   繁体   中英

Seemingly circular dependencies causing issues with Castle Windsor

I have a IUserService (and other services) that I am registering in bulk in my ServiceInstaller.cs:

  container.Register(
                AllTypes.FromAssemblyContaining<UserService>()
                .Where(type => type.Name.EndsWith("Service"))
                .WithService.DefaultInterface()
                .Configure(c => c.LifeStyle.Singleton)
                );

I then I have IAuthenticationService which I register as in my generic WindsorInstaller.cs file:

  container.Register(Component.For(typeof (IAuthenticationService))
                .ImplementedBy(typeof(AuthenticationService)));

Now things were working just fine until I added a public property for IAuthenticationService in my UserService.

It seems there is a circular dependacy or some timing issue of when things get registered, as I am getting the error:

Can't create component 'ABCD.Services.UserService' as it has dependencies to be satisfied.
ABCD.Services.UserService is waiting for the following dependencies:

Services:
- ABCD.Services.Interfaces.IAuthenticationService which was registered but is also waiting for dependencies.

ABCD.Services.AuthenticationService is waiting for the following dependencies:

Services:
- ABCD.Services.Interfaces.IUserService which was registered but is also waiting for dependencies. 

How can I solve this issue?

You need to either:

  1. Get rid of your circular dependencies (this is the preferred option), or
  2. Work around them, by using property injection, rather than constructor injection.

Using property injection (as illustrated in Steven's answer ) allows you to create instances of your classes without providing all the dependencies at the time of creation. The downside is that it is not as obvious to users of the class what they need to do to instantiate and fully configure the instance.

For a nice explanation of how to refactor to remove a ciruclar dependency see this blog post by Miško Hevery:

Property injection will solve your problem, because it breaks the dependency cycle. Just look at Krzysztof's example and try to instantiate a UserService ; You can't. Now take a look at the following example:

public class UserService
{
    UserService(AuthenticationService a) { }
}

public class AuthenticationService 
{
    AuthenticationService() { }

    public UserService UserService { get; set; }
}

In this example, the UserService dependency of the AuthenticationService is 'promoted' from a constructor argument to a property. Now you can create a user service like this:

var a = new AuthenticationService();
var s = new UserService(a);
a.UserService = s;

Breaking the circular dependency can be done with property injection and any dependency injection framework can be configured to allow property injection.

here's your scenario as I understand it:

public class UserService
{
   UserService(AuthenticationService a){}
}

public class AuthenticationService 
{
   AuthenticationService (UserService a){}
}

How would you create instances of both classes, creating at most single instance of each class?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM