简单注入器:循环图错误

时间:2016-12-10 02:32:57

标签: c# .net dependency-injection simple-injector

注册表:

insert into `accounts`(`username`,`password`,`access`,`hwid`,`ip`,`pcname`,`info`)
 values('bla','bla',1,'bla','bla','bla','bla');

第1课:

container.Register<IAuthenticationHandler, AuthenticationHandler>(Lifestyle.Transient);
container.Register<IUserHandler, UserHandler>(Lifestyle.Transient);    

第2课:

public UserHandler(IAuthenticationHandler authenticationHandler)
{
    _authenticationHandler = authenticationHandler;
} 

我理解循环问题是什么。初始化UserHandler时,它会注入AuthenticationHandler实现,然后尝试创建UserHandler实例并开始循环......

我的问题是我如何在(简单注射器)这种情况和其他我需要注射的情况下解决这个问题?

谢谢!

更新:

public AuthenticationHandler(IUserHandler userHandler)
{
    _userHandler = userHandler;
}

基本上我需要在AuthenticationHandler中调用UserHandler来获取用户并验证是否有用户。

我需要调用UserHandler中的AuthenticationHandler来获取salt和hash密码的函数。

我想我可以调用存储库来获取用户,但是如果在用户服务中完成了更多的操作,我就不应该通过服务处理程序

2 个答案:

答案 0 :(得分:3)

循环依赖性通常由SOLID原则违规引起,因为具有过宽接口和太多功能的类具有更高的机会来需要彼此的功能。

我相信在您的情况下情况也是如此,因为UserHandler.AddUser功能取决于AuthenticationHandler.GenerateRandomSaltHashPassword功能,而它与AuthenticationHandler的功能不同(即Authenticate)取决于UserHandler的另一个函数。这强烈表明IAuthenticationHandler抽象实际上违反了Interface Segregation Principle,其实施违反了Single Responsibility Principle

解决方案是将IAuthenticationHandler及其实现拆分为多个独立部分。例如

interface IPasswordUtilities {
    // NOTE: I believe GenerateRandomSalt is an implementation detail;
    // it should not be part of the interface
    string HashPassword(string plainPassword);
}

interface IAuthenticationHandler {
    void Authenticate(string username, string password);
}

class PasswordUtilities : IPasswordUtilities {
    // implementation
}

class AuthenticationHandler : IAuthenticationHandler {
    public AuthenticationHandler(IUserHandler userHandler, IPasswordUtilities utilities) { 
        ... 
    }
}

class UserHandler : IUserHandler {
    public UserHandler(IPasswordUtilities utilities) { ... }

    public void AddUser(User user) {
        string hashedPassword = _utilities.HashPassword(user.Password.HashedPassword);
    }
}

这将优雅地解决您的问题,因为您:

  • 通过将部分逻辑提取到更小的更集中的类
  • 来消除循环依赖性
  • 通过修复SRP和ISP违规行为,您可以使代码库更易于维护。

结束图将如下所示:

new AuthenticationHandler(
    new UserHandler(
        new PasswordUtilities()),
    new PasswordUtilities());

答案 1 :(得分:1)

处理此问题的一种方法是为一个或另一个实现一种方法来创建其依赖项的实例。

您可以在此处使用身份验证处理程序的抽象工厂,

public interface IAuthenticationHandlerFactory
{
    IAuthenticationHandler Create(IUserHandler userHandler);
}

public class AuthenticationHandlerFactory : IAuthenticationHandlerFactory
{
    public IAuthenticationHandler Create(IUserHandler userHandler)
    {
        return new AuthenticationHandler(userHandler);
    }
}

并将UserHandler更改为依赖于工厂

public class UserHandler : IUserHandler
{
    private IAuthenticationHandler _authenticationHandler;

    public UserHandler(IAuthenticationHandlerFactory authenticationHandler)
    {
        _authenticationHandler = authenticationHandler.Create(this);
    }
}

然后像往常一样在容器中注册,

container.Register<IAuthenticationHandlerFactory, AuthenticationHandlerFactory>(Lifestyle.Singleton);

这绝对 将工厂的具体实现耦合到身份验证处理程序。我保持这个相对简单,所以它不会过分复杂化。

另一种方法是使用委托类型。这样,您可以在组合根中保留对具体实现的引用。

UserHandler类将是

public class UserHandler : IUserHandler
{
    private IAuthenticationHandler _authenticationHandler;

    public UserHandler(Func<IUserHandler, IAuthenticationHandler> authenticationHandler)
    {
        _authenticationHandler = authenticationHandler(this);
    }
}

并且Func<,>的注册是

container.Register<Func<IUserHandler, IAuthenticationHandler>>(() => u => new AuthenticationHandler(u), Lifestyle.Singleton);