unity tag script herencia create clases .net inversion-of-control unity-container

.net - tag - unity herencia



Inyección de Setter/property en Unity sin atributos (8)

Estoy trabajando en un proyecto donde el marco de Unity se utiliza como el contenedor IoC. Mi pregunta se relaciona con la inyección de una dependencia opcional (en este caso, un registrador) en varias clases mediante inyección de propiedad o de configuración.

No quiero saturar los constructores de todas mis clases con estas dependencias opcionales, pero no puedo encontrar una buena manera de manejar esto en Unity. La forma en que lo haría es, de acuerdo con la documentación de MSDN , agregando un atributo a la propiedad:

private ILogger logger; [Dependency] public ILogger Logger { get { return logger; } set { logger = value; } }

Encuentro esto muy feo. En StructureMap uno podría hacer lo siguiente para establecer todas las propiedades de un tipo dado:

SetAllProperties(policy => policy.OfType<ILog>());

¿Alguien sabe si es posible hacer algo similar en Unity?

Editar:

Kim Major sugiere usar este enfoque, que también se puede lograr a través del código.

Me interesarían ejemplos de cómo hacerlo automáticamente para todas las propiedades coincidentes.



No me gustan esos atributos también

Puedes hacer todo usando el método Configure del contenedor de la unidad:

Primero registra el tipo

unityContainer.RegisterType<MyInterface,MyImpl>( new ContainerControlledLifetimeManager());

Si tienes varios constructores tendrás que hacer esto para que Unity invoque el constructor sin parámetros (si ninguno establece Unity irá para el más gordo)

unityContainer.Configure<InjectedMembers>() .ConfigureInjectionFor<MyImpl>( new InjectionConstructor());

Establecer la dependencia de la propiedad

unityContainer.Configure<InjectedMembers>() .ConfigureInjectionFor<MyImpl>( new InjectionProperty( "SomePropertyName", new ResolvedParameter<MyOtherInterface>()));

Configurar la dependencia del método

unityContainer.Configure<InjectedMembers>() .ConfigureInjectionFor<MyImpl>( new InjectionMethod( "SomeMethodName", new ResolvedParameter<YetAnotherInterface>()));


Puedes intentar esto:

este código en MyClass

[InjectionMethod] public void Initialize( [Dependency] ILogger logger

y luego llamarlo por:

unitycontainer.BuildUp<MyClass>(new MyClass());

unity llamará entonces al método Initialize con la dependencia del contenedor y luego podrá guardarlo en una variable privada en MyClass o algo así ...


El ejemplo original que publicó parece muy engorroso, pero puede usar propiedades implementadas automáticamente como esta para ayudar a limpiar ese código:

[Dependency] public ILogger Logger { get; set; }


Con Unity 2.1 esto funcionaría también:

var container = new UnityContainer() .RegisterType<ILogger, Logger>() .RegisterType<ISomeInterface, SomeImplementaion>( new InjectionProperty("Logger", new ResolvedParameter<ILogger>()));

La propiedad inyectada de la clase SomeImplementaion es solo

public ILogger Logger { get; set; }


Tampoco me gusta mucho el uso de atributos, pero tampoco me gusta el .Configure<InjectedMembers>() porque está vinculado a un nombre de propiedad específico y a un valor específico. La forma en que he encontrado que te da la mayor flexibilidad es crear tu propia estrategia de desarrollador.

Creé esta clase simple que itera las propiedades de un objeto que se está construyendo y establece sus valores de propiedad si el tipo de esa propiedad se ha registrado con el contenedor de unidad.

public class PropertyInjectionBuilderStrategy:BuilderStrategy { private readonly IUnityContainer _unityContainer; public PropertyInjectionBuilderStrategy(IUnityContainer unityContainer) { _unityContainer = unityContainer; } public override void PreBuildUp(IBuilderContext context) { if(!context.BuildKey.Type.FullName.StartsWith("Microsoft.Practices")) { PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(context.BuildKey.Type); foreach (PropertyDescriptor property in properties) { if(_unityContainer.IsRegistered(property.PropertyType) && property.GetValue(context.Existing) == null) { property.SetValue(context.Existing,_unityContainer.Resolve(property.PropertyType)); } } } } }

Usted registra su BuilderStrategy creando un UnityContainerExtension . Aquí hay un ejemplo:

public class TestAppUnityContainerExtension:UnityContainerExtension { protected override void Initialize() { Context.Strategies.Add(new PropertyInjectionBuilderStrategy(Container), UnityBuildStage.Initialization); } }

Eso se registra con el contenedor de Unity como tal:

IUnityContainer container = new UnityContainer(); container.AddNewExtension<TestAppUnityContainerExtension>();

Espero que esto ayude,
Matthew


Puedes inyectar tu clase con el contenedor de la unidad.

por ejemplo, si tiene una clase "MyClass" y tiene una dependencia en dos interfaces "IExample1" y "IExample2" y no quiere definir un parámetro para ellos en el constructor, entonces siga los pasos a continuación

Paso 1. Registrar ambas interfaces en el contenedor de la unidad

IUnityContainer container = new UnityContainer(); container.RegisterType<IExample1,Impl1>(); container.RegisterType<IExample2,Impl2>(); //resolve class MyClass var myClass = container.Resolve<MyClass>();


Paso 2. Tu clase debería verse así

public class MyClass { IExample1 ex1; IExample2 ex2 public MyClass(IUnityContainer container) { /* This unity container is same unity container that we used in step 1 to register and resolve classes. So you can use this container to resolve all the dependencies. */ ex1= container.Resolve<IExample1>(); // will give you object of Impl1 ex2= container.Resolve<IExample2>(); // will give you object of Impl2 } }

Paso 3 De esta forma, puede resolver cualquier cantidad de dependencias sin definirlas en el constructor.


Eche un vistazo al proyecto UnityConfiguration para la configuración basada en convenciones. Funciona bastante bien, aunque tengo un problema al buscar varias implementaciones usando ResolveAll<IType>() . Ver esta pregunta .

container.RegisterInstance(typeof (ILogger), LoggerService.GetLogger()); container.Configure(c => c.Scan(scan => { scan.AssembliesInBaseDirectory(a => a.FullName.StartsWith("My.Company")); // Filter out everthing that are not from my assemblies scan.InternalTypes(); scan.With<SetAllPropertiesConvention>().OfType<ILogger>(); }));