2016-12-10 8 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インスタンスが作成され、サイクルが開始されます。

私はこの問題をどのように解決しますか?どこで私はこのように注射する必要がありますか?

ありがとうございました!

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

は悪循環を断ち切る方法を示すために、例の多くを必要とするだろう。私が確かに言うことができる1つのヒントは、あなたのDIコンテナの選択はここでは重要ではないということです。 – jdphenix

答えて

3

巡回依存関係は、多くの場合、あまりにも広範なインターフェースと、あまりにも多くの機能を持つクラス以来、SOLID原則違反によって引き起こされていますお互いの機能を必要とする可能性がはるかに高い。 UserHandlerからさらに別の機能に依存し

それはAuthenticationHandler(すなわちAuthenticate)とは異なる機能である一方、UserHandler.AddUser機能は、AuthenticationHandler.GenerateRandomSaltHashPassword機能に依存するため、私は、これは同様にあなたの状況の場合であると信じています。これは、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); 

これは絶対にですは、ファクトリの具体的な実装を認証ハンドラに結合します。私はこれを比較的シンプルに保つので、合併症には行き渡りません。


これを行うもう1つの方法は、デリゲートタイプです。このようにして、コンポジションルートに具体的な実装への参照を保持することができます。

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

関連する問題