Unità dell’iniezione delle dipendenze – Risoluzione condizionale

La risoluzione condizionale è l’ultima cosa che non capisco al momento.

Diciamo che abbiamo un’interfaccia IAuthenticate :

 public interface IAuthenticate{ bool Login(string user, string pass); } 

Ora ho due tipi di autenticazione.

Autenticazione di Twitter

 public class TwitterAuth : IAuthenticate { bool Login(string user, string pass) { //connect to twitter api } } 

Autentica di Facebook

 public class FacebookAuth: IAuthenticate { bool Login(string user, string pass) { //connect to fb api } } 

Registrazione dei tipi nella configurazione dell’unità:

 unityContainer.RegisterType(); unityContainer.RegisterType(); 

iniettare oggetti tramite DI nel nostro controller:

 private readonly IAuthenticate _authenticate; public AuthenticateController(IAuthenticate authenticate) { _authenticate = authenticate; } // login with twitter public virtual ActionResult Twitter(string user, string pass) { bool success = _authenticate.Login(user, pass); } // login with fb public virtual ActionResult Facebook(string user, string pass) { bool success = _authenticate.Login(user, pass); } // login with google public virtual ActionResult Google(string user, string pass) { bool success = _authenticate.Login(user, pass); } 

In che modo esattamente l’unità sa quale object deve risolvere per diversi tipi di autenticazione? Come faccio a risolvere condizionatamente in questo caso?

Ho parlato con un mio amico, e ha spiegato se questa situazione sembra essere un progetto sbagliato, ma questo è solo il modello di fabbrica usato.

Un modo semplice per risolvere questo è con il modello di strategia . Si noti che è ansible aggiungere o rimuovere provider di accesso senza modificare il progetto: è sufficiente modificare la configurazione DI.

interfacce

 public interface IAuthenticate{ bool Login(string user, string pass); bool AppliesTo(string providerName); } public interface IAuthenticateStrategy { bool Login(string providerName, string user, string pass); } 

Autentica Provider

 public class TwitterAuth : IAuthenticate { bool Login(string user, string pass) { //connect to twitter api } bool AppliesTo(string providerName) { // I used the type name for this example, but // note that you could use any string or other // datatype to select the correct provider. return this.GetType().Name.Equals(providerName); } } public class FacebookAuth: IAuthenticate { bool Login(string user, string pass) { //connect to fb api } bool AppliesTo(string providerName) { return this.GetType().Name.Equals(providerName); } } 

Strategia

 public class AuthenticateStrategy: IAuthenticateStrategy { private readonly IAuthenticate[] authenticateProviders; public AuthenticateStrategy(IAuthenticate[] authenticateProviders) { if (authenticateProviders == null) throw new ArgumentNullException("authenticateProviders"); this.authenticateProviders = authenticateProviders; } public bool Login(string providerName, string user, string pass) { var provider = this.authenticateProviders .FirstOrDefault(x => x.AppliesTo(providerName)); if (provider == null) { throw new Exception("Login provider not registered"); } return provider.Login(user, pass); } } 

Registrazione di unità

 // Note that the strings used here for instance names have nothing // to do with the strings used to select the instance in the strategy pattern unityContainer.RegisterType("twitterAuth"); unityContainer.RegisterType("facebookAuth"); unityContainer.RegisterType( new InjectionConstructor( new ResolvedArrayParameter( new ResolvedParameter("twitterAuth") ), new ResolvedArrayParameter( new ResolvedParameter("facebookAuth") ) )); 

uso

 private readonly IAuthenticateStrategy _authenticateStrategy; public AuthenticateController(IAuthenticateStrategy authenticateStrategy) { if (authenticateStrategy == null) throw new ArgumentNullException("authenticateStrategy"); _authenticateStrategy = authenticateStrategy; } // login with twitter public virtual ActionResult Twitter(string user, string pass) { bool success = _authenticateStrategy.Login("TwitterAuth", user, pass); } // login with fb public virtual ActionResult Facebook(string user, string pass) { bool success = _authenticateStrategy.Login("FacebookAuth", user, pass); } 

L’unità non lo farà senza il tuo aiuto. È ansible fornire un nome quando si registrano i tipi IAuthenticate:

 unityContainer.RegisterType("Twitter"); unityContainer.RegisterType("Facebook"); 

Non vorrai più inserire direttamente un’istanza IAuthenticate in AuthenticateController. Otterrai l’istanza desiderata in base a una condizione appena fuori dall’unità (stile di localizzazione del servizio):

 myContainer.Resolve("Twitter"); 

o ti inietterai una fabbrica che fa questo per te (se ti piace uno stile DI rigoroso).