Unidad de dependency injection: resolución condicional

La resolución condicional es lo último que no entiendo en este momento.

Digamos que tenemos una interfaz IAuthenticate :

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

Ahora tengo dos tipos de autenticación.

Twitter auth

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

Facebook Auth

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

Registrando tipos en la configuración de la unidad:

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

inyectar objetos a través de DI en nuestro controlador:

 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); } 

¿Cómo sabrá la unidad qué objeto tiene que resolver para los diferentes tipos de autenticación? ¿Cómo hago una resolución condicional en este caso?

Hablé con un amigo mío, y me explicó si esta situación parece ser un diseño incorrecto, pero esto es solo un patrón de fábrica utilizado.

Una forma simple de resolver esto es con el patrón de estrategia . Tenga en cuenta que puede agregar o eliminar proveedores de inicio de sesión sin cambiar el diseño; solo necesita cambiar la configuración de DI.

Interfaces

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

Autenticar proveedores

 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); } } 

Estrategia

 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); } } 

Registro de Unidad

 // 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); } 

La unidad no lo hará sin tu ayuda. Podría proporcionar un nombre cuando registre sus tipos IAuthenticate:

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

Ya no deseará inyectar directamente una instancia IAuthenticate en AuthenticateController. Obtendrá la instancia que desee en función de una condición que esté fuera de la unidad (estilo del localizador de servicios):

 myContainer.Resolve("Twitter"); 

o inyectará una Fábrica que lo haga por usted (si le gusta un estilo DI estricto).