2010-06-30 8 views
5

tengo el siguiente código en mi Global.aspxinyección Propiedad en Controlador Base utilizando Ninject 2

protected override void OnApplicationStarted() 
{ 
    AreaRegistration.RegisterAllAreas(); 
    RegisterRoutes(RouteTable.Routes); 
    RegisterAllControllersIn(Assembly.GetExecutingAssembly()); 
} 

protected override IKernel CreateKernel() 
{ 
    return new StandardKernel(new ServiceModule()); 
} 

también tengo la siguiente Ninject Módulo:

internal class ServiceModule : NinjectModule 
{ 
    public override void Load() 
    { 
     Bind<IProductService>().To<ProductService>().InRequestScope(); 
    } 
} 

también tengo una base:

public class BaseController : Controller 
{ 
    [Inject] 
    public IProductService ProductService 
    { 
     get; 
     set; 
    } 
} 

Este código funciona. El problema que tengo es que me gustaría eliminar el atributo de inyección del controlador base y especificarlo en el Ninject ServiceModule. En otras palabras, ¿cómo voy a escribir una regla vinculante en el ServiceModule que le dice a Ninject que inyecte ProductService en la propiedad en el controlador base?

Si elimino el atributo obtendré una NullReferenceException.

Respuesta

3

Encuadernación basada en convenciones vive en http://github.com/ninject/ninject.extensions.conventions - uno implementa IBindingGenerator. Sin embargo, esto está relacionado con el descubrimiento de interfaces y servicios.

En general, la inyección de constructor es un buen enfoque predeterminado. Sin embargo, la manera en que funciona ASP.NET MVC hace que sea más difícil hacerlo (por lo tanto, FubuMVC, etc.). Entonces, la inyección de propiedades es la siguiente mejor opción.

Puede encontrar que usar OnActivation en su Bind puede permitirle hacer lo suficiente, y si puede, este es de lejos el más simple.

Caracterizaría lo que intenta hacer como activación basada en convenciones. El problema es:

  • decidir lo que se va a autoinyectar. ¿Vas a inyectar todo lo público que no sea concreto? ¿Todo lo que sabe tu Kernel? A menos que pueda obtener una definición clara de lo que quiere hacer, el proceso de inyección puede volverse impredecible y difícil de entender. Terminas depurando y explicando mucho a tus colegas.

  • por lo que es eficiente. Ninject genera código dinámicamente entre bastidores para hacer que la activación de una instancia sea eficiente (es decir, en el momento de andar la clase buscando marcadores [Inject], genera código una vez para hacer lo que luego se jima como si lo hubiera escrito a mano).

Buscando en el código, no hay una manera fácil OOTB. Parece que agregar un IInjectionHeuristic personalizado haría el truco.

Sin embargo, si usted está recibiendo este profundo en contenedores, es necesario

  1. pausa y ver si se puede mantener la sencillez por no ir por este camino
  2. ir a la lista de correo y ninject búsqueda para cosas similares
  3. si aún desea hacerlo, envíe un correo allí.
+0

Ruben, ¿me puede dar un ejemplo de cómo escribiría una regla vinculante en el ServiceModule que le dice a Ninject que inyecte ProductService en la propiedad en el controlador base? ¡Gracias! – Thomas

+0

@Thomas: Nunca he hecho una personalización de esa naturaleza (y como no creo que sea un buen enfoque no deseo), desafortunadamente no podré hacer el tiempo para hacerlo, lo siento ... (Y como mi respuesta parece haber sido juzgada como sin valor hasta ahora, ¿por qué habría de hacerlo? ¿No es que tengo algún comentario de que mi respuesta se ha entendido o es correcta?) –

2

Al ampliar las ideas de Ruben Bartelink, puede crear una implementación personalizada de IInjectionHeuristic.

public class ControllerInjectionHeuristic : NinjectComponent, IInjectionHeuristic 
{ 
    private readonly IKernel kernel; 

    public BaseControllerInjectionHeuristic(IKernel kernel) 
    { 
     this.kernel = kernel; 
    } 

    public bool ShouldInject(MemberInfo member) 
    { 
     if (member.ReflectedType != typeof(BaseController)) 
     { 
      return false; 
     } 

     var propertyInfo = member.ReflectedType.GetProperty(member.Name); 
     object service = kernel.TryGet(propertyInfo.PropertyType); 

     return service != null; 
    } 
} 

El ControllerInjectionHeuristic inyectará cualquier propiedad (servicio) en BaseController para los que el núcleo es capaz de resolver el servicio.

Registre la implementación personalizada con el kernel.

var kernel = new StandardKernel(); 
kernel.Components.Add<IInjectionHeuristic, ControllerInjectionHeuristic>(); 

Otra solución al problema es utilizar OnActivation. (Esta solución no se ha probado, pero debería darle una idea sobre cómo proceder).

+0

+1 Buen trabajo que proporciona una muestra en lugar de divagaciones como yo ! Sin embargo, no estoy seguro de si la forma de convertir la búsqueda de PropertyInfo desde el MemberInfo es correcta, ¿quizás debería usar 'is' /' as'? Además, un 'TryGet' hará una acumulación completa de objetos que se te pasará por el camino. Desea una operación CanResolve (que no puedo pensar en el nombre). En este caso, creo que a primera vista está bien, pero personalmente me gustaría dedicar unos minutos a leer minuciosamente los documentos de MSDN para '.ReflectedType' para averiguar si eso es ** Exactamente ** lo que quiero decir. –

+0

Pensé que sería una buena oportunidad para aprender algo. La razón por la que hago 'var propertyInfo = member.ReflectedType.GetProperty (member.Name);' es porque, en mi proyecto de prueba, 'member' resultó ser' RuntimePropertyInfo', que es una clase interna. Así que solo corrí con la siguiente mejor cosa que se me ocurre. Elegí 'kernel.TryService (Type)' en lugar de 'kernel.CanResolve (IRequest)' porque era más simple que construir una solicitud completa. Sin embargo, supongo que 'ControllerInjectorHeuristic' no funcionará muy bien. Definitivamente no está listo para la producción. – mrydengren

Cuestiones relacionadas