2016-12-10 14 views
3

註冊地:簡單的注射器:循環圖錯誤

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

第1類:

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

2類:

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

我明白什麼叫做循環問題是。當UserHandler初始化時,它注入AuthenticationHandler實現,然後嘗試創建UserHandler實例並開始循環...

我的問題是我該如何解決這個問題(SIMPLE INJECTOR)這種情況和其他我需要像這樣注入?

謝謝!

UPDATE:

function AddUser(User user){ // User Handler 
    _authenticationHandler.GenerateRandomSalt(); 
    string hashedPassword = _authenticationHandler.HashPassword(user.Password.HashedPassword, salt); 
} 

function Authenticate(string username, string password){ // Authentication Handler 
    _userHandler.GetUserByUsername(username?.Trim()); 
} 

Bascially我需要調用中的AuthenticationHandler的UserHandler來獲取用戶,並確認有用戶。

我需要調用UserHandler中的AuthenticationHandler來獲取函數來加密和散列密碼。

我想我可以調用庫,以獲取用戶,但我不應該去通過的情況下,更多的東西在用戶服務做處理這個

+1

將需要更多的例子來說明如何打破這個循環。我可以肯定地說的一個暗示是,你選擇DI容器在這裏並不重要。 – jdphenix

回答

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

謝謝!我將把哈希分成另一個處理程序。仍在學習最佳實踐。再次感謝! – user3330265

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); 
+0

明天我會試試這個。謝謝! – user3330265