c# - mvc - Ninject. Inyección opcional
ninject mvc 5 (2)
Tengo indicadores globales que habilitan / deshabilitan funciones. Me gustaría inyectar algunas dependencias dependiendo de alguna bandera. Algunas características requieren clases que están muy construidas, por lo que quiero inyectar nulo si el valor del indicador es falso y la dependencia real de lo contrario Ninject no permite la inyección nula. ¿Hay más opciones?
Actualización: los argumentos del constructor se pueden decorar con el atributo OptionalAttribute
. En este caso, se inyecta nulo si no se encuentra un enlace correspondiente. Hay un problema aquí: no puedo verificar si la clase objetivo se puede construir correctamente. Tengo una prueba para cada dependencia pública que verifica si se puede construir con éxito. En caso de que el valor de la bandera sea verdadero, no podré encontrar el error cuando la dependencia decorada con el atributo de atributo OptionalAttribute
no se pueda construir correctamente. Me gustaría manejarlo solo a nivel de enlace.
Inyectar nulo no suele ser una buena idea. Esto contaminará su código con verificaciones si el objeto es nulo o no, como se muestra en el siguiente código:
public interface IFoo
{
void Do();
}
public class Foo : IFoo
{
public void Do()
{
DoSomething();
}
}
public class UglyNullCheckingBar
{
IFoo foo;
public Bar(IFoo foo)
{
this.foo = foo;
}
public void Do()
{
if (this.foo != null)
{
this.foo.Do();
}
}
}
La mejor manera en este caso es implementar un objeto nulo que no haga absolutamente nada e inyectar éste en lugar de nulo. Esto mantiene su código limpio.
public class NullFoo : IFoo
{
public void Do() {}
}
public class Bar
{
IFoo foo;
public Bar(IFoo foo)
{
this.foo = foo;
}
public void Do()
{
this.foo.Do();
}
}
Puede variar el comportamiento de la inyección mediante el enlace utilizando un método de fábrica (es decir, ToMethod
), y es posible permitir la inyección de AllowNullInjection
nulos mediante la configuración de la configuración Permitir la inyección del contenedor.
Otra alternativa sería utilizar un método de fábrica y suministrar un objeto ficticio ligero en lugar de su clase de peso pesado. Si está utilizando interfaces, esto sería sencillo, solo tenga implementaciones de la interfaz que no hagan nada. Incluso podrías usar un marco de burla como FakeItEasy para construir estos maniquíes para ti. El beneficio aquí es que el dummy hace que el comportamiento especial sea transparente para los clientes, es decir, los clientes no necesitan verificar el null
, etc.
Un ejemplo del uso de un método de fábrica, más AllowNullInjection
y nulls:
public void Configure()
{
bool create = true;
IKernel kernel = new StandardKernel();
kernel.Settings.AllowNullInjection = true;
kernel.Bind<IFoo>().ToMethod(ctx => create ? ctx.Kernel.Get<Foo>() : null);
DependendsOnIFoo depFoo = kernel.Get<DependendsOnIFoo>();
}
private interface IFoo {}
private class Foo : IFoo {}
private class DependendsOnIFoo
{
public DependendsOnIFoo(IFoo foo) {}
}
Y un ejemplo donde se sustituye un objeto ligero dependiendo de la bandera:
public void Configure()
{
bool heavy = true;
IKernel kernel = new StandardKernel();
kernel.Bind<IFoo>()
.ToMethod(ctx => heavy ? ctx.Kernel.Get<HeavyFoo>() : (IFoo)new DummyFoo());
DependendsOnIFoo depFoo = kernel.Get<DependendsOnIFoo>();
}
private interface IFoo {}
private class HeavyFoo : IFoo {}
private class DummyFoo : IFoo { }
private class DependendsOnIFoo
{
public DependendsOnIFoo(IFoo foo) {}
}