Castillo de Windsor:¿Cómo especificar un parámetro de constructor a partir del código?
-
01-07-2019 - |
Pregunta
Digamos que tengo la siguiente clase
MyComponent : IMyComponent {
public MyComponent(int start_at) {...}
}
Puedo registrar una instancia con Castle Windsor a través de xml de la siguiente manera
<component id="sample" service="NS.IMyComponent, WindsorSample" type="NS.MyComponent, WindsorSample">
<parameters>
<start_at>1</start_at >
</parameters>
</component>
¿Cómo haría exactamente lo mismo pero en código?(Aviso, el parámetro constructor)
Solución
Editar:Usé las respuestas a continuación del código con Fluent Interface :)
namespace WindsorSample
{
using Castle.MicroKernel.Registration;
using Castle.Windsor;
using NUnit.Framework;
using NUnit.Framework.SyntaxHelpers;
public class MyComponent : IMyComponent
{
public MyComponent(int start_at)
{
this.Value = start_at;
}
public int Value { get; private set; }
}
public interface IMyComponent
{
int Value { get; }
}
[TestFixture]
public class ConcreteImplFixture
{
[Test]
void ResolvingConcreteImplShouldInitialiseValue()
{
IWindsorContainer container = new WindsorContainer();
container.Register(
Component.For<IMyComponent>()
.ImplementedBy<MyComponent>()
.Parameters(Parameter.ForKey("start_at").Eq("1")));
Assert.That(container.Resolve<IMyComponent>().Value, Is.EqualTo(1));
}
}
}
Otros consejos
Prueba esto
int start_at = 1;
container.Register(Component.For().DependsOn(dependency: Dependency.OnValue(start_at)));
¿Ha considerado utilizar Binsor para configurar su contenedor?En lugar de XML detallado y torpe, puede configurar Windsor utilizando un DSL basado en Boo.Así es como se verá tu configuración:
component IMyComponent, MyComponent:
start_at = 1
La ventaja es que tiene un archivo de configuración maleable pero evita los problemas con XML.Además, no es necesario volver a compilar para cambiar la configuración como lo haría si configurara el contenedor en el código.
También hay muchos métodos auxiliares que permiten la configuración de fricción cero:
for type in Assembly.Load("MyApp").GetTypes():
continue unless type.NameSpace == "MyApp.Services"
continue if type.IsInterface or type.IsAbstract or type.GetInterfaces().Length == 0
component type.GetInterfaces()[0], type
Puedes empezar con ello. aquí.
Debe pasar un IDictionary cuando le solicite la instancia al contenedor.
Usarías esta sobrecarga de resolución del IWindsorContainer:
T Resolve<T>(IDictionary arguments)
o el no genérico:
object Resolve(Type service, IDictionary arguments)
Así por ejemplo:(suponiendo que el contenedor sea un IWindsorContainer)
IDictionary<string, object> values = new Dictionary<string, object>();
values["start_at"] = 1;
container.Resolve<IMyComponent>(values);
Tenga en cuenta que los valores clave del diccionario distinguen entre mayúsculas y minúsculas.
Podrías usar una clase de configuración para leer app.config.Luego regístrelo y haga que Windsor lo use para su dependencia.Lo ideal sería que mi MyConfiguration usara una interfaz.
public class MyConfiguration
{
public long CacheSize { get; }
public MyConfiguration()
{
CacheSize = ConfigurationManager.AppSettings["cachesize"].ToLong();
}
}
container.Register(Component.For<MyConfiguration>().ImplementedBy<MyConfiguration>());
container.Register(Component.For<MostRecentlyUsedSet<long>>()
.ImplementedBy<MostRecentlyUsedSet<long>>().
DependsOn(Dependency.OnValue("size", container.Resolve<MyConfiguration>().CacheSize))
.LifestyleSingleton());
Puede utilizar el método AddComponentWithProperties de la interfaz IWindsorContainer para registrar un servicio con propiedades extendidas.
A continuación se muestra un ejemplo "funcional" de cómo hacer esto con una prueba unitaria NUnit.
namespace WindsorSample
{
public class MyComponent : IMyComponent
{
public MyComponent(int start_at)
{
this.Value = start_at;
}
public int Value { get; private set; }
}
public interface IMyComponent
{
int Value { get; }
}
[TestFixture]
public class ConcreteImplFixture
{
[Test]
void ResolvingConcreteImplShouldInitialiseValue()
{
IWindsorContainer container = new WindsorContainer();
IDictionary parameters = new Hashtable {{"start_at", 1}};
container.AddComponentWithProperties("concrete", typeof(IMyComponent), typeof(MyComponent), parameters);
IMyComponent resolvedComp = container.Resolve<IMyComponent>();
Assert.That(resolvedComp.Value, Is.EqualTo(1));
}
}
}