c# - visual - ¿Puedo pasar los parámetros del constructor al método Resolve() de Unity?
unity container resolve with parameters (7)
<2 centavos>
¿Qué pasa si luego decides utilizar un servicio diferente que requiere más o menos que solo el contexto?
El problema con los parámetros del constructor y el IoC es que los parámetros están vinculados al tipo concreto que se utiliza, en lugar de ser parte del contrato que define la interfaz del servicio.
Mi sugerencia sería que usted también resuelva el contexto, y creo que Unity debería tener una forma de evitar crear 3 instancias del mismo, o debería considerar un servicio de fábrica que tenga una forma de construir el objeto.
Por ejemplo, ¿qué ocurre si luego decide construir un repositorio que no se base en absoluto en una base de datos tradicional, sino que utiliza un archivo XML para generar datos ficticios para la prueba? ¿Cómo harías para alimentar el contenido XML a ese constructor?
IoC se basa en el código de desacoplamiento, vinculando el tipo y la semántica de los argumentos a los tipos concretos, realmente no se ha realizado el desacoplamiento correctamente, todavía hay una dependencia.
"Este código puede hablar con cualquier tipo de repositorio, siempre que implemente esta interfaz ... Ah, y usa un contexto de datos".
Ahora, sé que otros contenedores IoC tienen soporte para esto, y lo tuve en mi primera versión también, pero en mi opinión, no pertenece al paso de resolución.
</ 2 centavos>
Estoy usando Unity de Microsoft para la inyección de dependencias y quiero hacer algo como esto:
IDataContext context = _unityContainer.Resolve<IDataContext>();
var repositoryA = _unityContainer.Resolve<IRepositoryA>(context); //Same instance of context
var repositoryB = _unityContainer.Resolve<IRepositoryB>(context); //Same instance of context
IDataContext context2 = _unityContainer.Resolve<IDataContext>(); //New instance
var repositoryA2 = _unityContainer.Resolve<IRepositoryA>(context2);
RepositoryA
y RepositoryB
tienen un constructor que toma un parámetro IDataContext
, y quiero que Unity inicialice el repositorio con el contexto en el que lo paso. También tenga en cuenta que IDataContext
no está registrado en Unity (no quiero 3 instancias de IDataContext
).
A partir de hoy, han agregado esta funcionalidad:
Está en la última gota aquí:
http://unity.codeplex.com/SourceControl/changeset/view/33899
Discusión sobre esto aquí:
http://unity.codeplex.com/Thread/View.aspx?ThreadId=66434
Ejemplo:
container.Resolve<IFoo>(new ParameterOverrides<Foo> { { "name", "bar" }, { "address", 42 } });"
Gracias chicos ... el mío es similar a la publicación de "Exist". Vea abajo:
IUnityContainer container = new UnityContainer();
container.LoadConfiguration();
_activeDirectoryService = container.Resolve<IActiveDirectoryService>(new ResolverOverride[]
{
new ParameterOverride("activeDirectoryServer", "xyz.adserver.com")
});
La respuesta muy corta es: no. Actualmente, Unity no tiene forma de pasar parámetros al constructor que no son constantes o inyectados, que he podido encontrar. En mi humilde opinión, esa es la única gran cosa que falta, pero creo que es por diseño y no por omisión.
Como señala Jeff Fritz, en teoría podría crearse un administrador de por vida personalizado que sepa qué instancia de contexto inyectar en varios tipos, pero ese es un nivel de codificación difícil que parece obviar el propósito de usar Unity o DI en primer lugar.
Podría dar un paso atrás respecto de la DI completa y hacer que las implementaciones de repositorio sean responsables de establecer sus propios contextos de datos. La instancia de contexto aún se puede resolver desde el contenedor, pero la lógica para decidir cuál usar debería ir a la implementación del repositorio. No es tan puro, sin duda, pero eliminaría el problema.
NotDan, creo que puede haber respondido su propia pregunta en comentarios a lassevk.
Primero, utilizaría un LifetimeManager para administrar el ciclo de vida y el número de instancias de IDataContext que crea Unity.
http://msdn.microsoft.com/en-us/library/cc440953.aspx
Parece que el objeto ContainerControlledLifetimeManager
le proporcionará la administración de instancias que necesita. Con ese LifetimeManager en su lugar, Unity debería agregar la misma instancia de IDataContext a todos los objetos que requieren una dependencia IDataContext.
Otra alternativa que podría usar (no sé si es una buena práctica o no) es crear dos contenedores y registrar una instancia para cada uno:
IDataContext context = _unityContainer.Resolve<IDataContext>();
_unityContainer.RegisterInstance(context);
var repositoryA = _unityContainer.Resolve<IRepositoryA>(); //Same instance of context
var repositoryB = _unityContainer.Resolve<IRepositoryB>(); //Same instance of context
//declare _unityContainer2
IDataContext context2 = _unityContainer2.Resolve<IDataContext>(); //New instance
_unityContainer2.RegisterInstance(context2);
var repositoryA2 = _unityContainer2.Resolve<IRepositoryA>(context2); //will retrieve the other instance
Espero que esto ayude también
Puede usar InjectionConstructor / InjectionProperty / InjectionMethod dependiendo de su Injection Architecture dentro de ResolvedParameter <T> ("name") para obtener una instancia de un objeto previamente registrado en el contenedor.
En su caso, este Objeto debe estar registrado con un Nombre, y por el mismo escollo necesita ContainerControlledLifeTimeManager () como LifeTimeManager.
_unityContainer.RegisterType<IDataContext,DataContextA>("DataContextA", new ContainerControlledLifeTimeManager());
_unityContainer.RegisterType<IDataContext,DataContextB>("DataContextB");
var repositoryA = _unityContainer.Resolve<IRepositoryA>(new InjectionConstructor(
new ResolvedParameter<IDataContext>("DataContextA")));
var repositoryB = _unityContainer.Resolve<IRepositoryB>(new InjectionConstructor(
new ResolvedParameter<IDataContext>("DataContextA")));
var repositoryA2 = _unityContainer.Resolve<IRepositoryA>(new InjectionConstructor(
new ResolvedParameter<IDataContext>("DataContextB")));