c# - ninjectwebcommon - Cómo usar Ninject
ninject mvc example (3)
He intentado usar Ninject hoy y tengo un par de preguntas. Antes que nada, necesito usar el atributo Inject en todos los constructores para los que quiero usar inyección. Esto parece un diseño realmente cojo? ¿Necesito crear un Kernel y luego usarlo en todos los lugares donde paso en una clase inyectada?
Antes que nada, necesito usar el atributo Inject en todos los constructores para los que quiero usar inyección. Esto parece un diseño realmente cojo?
No, no deberías tener que hacer esto en realidad. Como trabajas con ASP.NET MVC, puedes instalar el paquete Ninget.MVC3 Nuget. Esto te permitirá comenzar con una clase NinjectMVC3
en la carpeta App_Start. Puede usar el método RegisterServices
para registrar sus interfaces / clases con Ninject. Todos los controladores que tienen dependencias a esas interfaces se resolverán automáticamente por Ninject, no es necesario el atributo Inject.
¿Necesito crear un Kernel y luego usarlo en todos los lugares donde paso en una clase inyectada?
No, lo que estás describiendo suena más como el patrón de Localizador de servicios , no como una inyección de dependencia; querrás pasar tus dependencias idealmente en el constructor, en lugar de resolverlas dentro de clases particulares utilizando el kernel. Debería haber una sola raíz de composición central donde se realiza la resolución, que está dentro de la raíz de composición ya sea en el método RegisterServices
mencionado anteriormente o en un módulo Ninject separado instanciado allí; el enfoque posterior le permitirá un poco más de flexibilidad y modularidad (sin juego de palabras previsto) para cambiar la forma de resolver sus dependencias.
Aquí hay un buen tutorial para principiantes sobre la inyección de dependencia con Ninject y MVC3 .
La mejor manera de comenzar con Ninject es comenzar pequeño. Busque una new
.
En algún lugar en el medio de tu aplicación, estás creando una clase dentro de otra clase. Eso significa que estás creando una dependencia . Inyección de dependencia se trata de pasar en esas dependencias, generalmente a través del constructor, en lugar de incrustarlas .
Supongamos que tiene una clase como esta, utilizada para crear automáticamente un tipo de nota específico en Word. (Esto es similar a un proyecto que he hecho en el trabajo recientemente.)
class NoteCreator
{
public NoteHost Create()
{
var docCreator = new WordDocumentCreator();
docCreator.CreateNewDocument();
[etc.]
WordDocumentCreator
es una clase que maneja los detalles de la creación de un nuevo documento en Microsoft Word (crea una instancia de Word, etc.). Mi clase, NoteCreator
, depende de WordDocumentCreator
para realizar su trabajo.
El problema es que, si algún día decidimos pasar a un procesador de texto superior, tengo que buscar todos los lugares donde se WordDocumentCreator
una instancia de WordDocumentCreator
y cambiarlos para crear una instancia de WordPerfectDocumentCreator
lugar.
Ahora imagina que cambio mi clase para que se vea así:
class NoteCreator
{
WordDocumentCreator docCreator;
public NoteCreator(WordDocumentCreator docCreator) // constructor injection
{
this.docCreator = docCreator;
}
public NoteHost Create()
{
docCreator.CreateNewDocument();
[etc.]
Mi código no ha cambiado tanto; todo lo que hice en el método Create
es eliminar la línea con la new
. Pero ahora estoy inyectando mi dependencia. Hagamos un pequeño cambio más:
class NoteCreator
{
IDocumentCreator docCreator;
public NoteCreator(IDocumentCreator docCreator) // change to interface
{
this.docCreator = docCreator;
}
public NoteHost Create()
{
docCreator.CreateNewDocument();
[etc.]
En lugar de pasar un WordDocumentCreator
concreto , he extraído una interfaz IDocumentCreator
con un método CreateNewDocument
. Ahora puedo pasar en cualquier clase que implemente esa interfaz, y todo lo que NoteCreator
tiene que hacer es llamar al método que conoce.
Ahora la parte difícil . Ahora debería tener un error de compilación en mi aplicación, porque en algún lugar estaba creando NoteCreator
con un constructor sin parámetros que ya no existe . Ahora necesito sacar esa dependencia también. En otras palabras, paso por el mismo proceso que el anterior , pero ahora lo estoy aplicando a la clase que crea un nuevo NoteCreator
. Cuando comiences a extraer dependencias, verás que tienden a "burbujear" hasta la raíz de tu aplicación, que es el único lugar donde debes tener una referencia a tu contenedor DI (por ejemplo, Ninject).
La otra cosa que tengo que hacer es configurar Ninject . La pieza esencial es una clase que se ve así:
class MyAppModule : NinjectModule
{
public override void Load()
{
Bind<IDocumentCreator>()
.To<WordDocumentCreator>();
Esto le dice a Ninject que cuando intento crear una clase que, en algún momento, requiere un IDocumentCreator
, debe crear un WordDocumentCreator
y usarlo. El proceso por el cual pasa Ninject se ve así:
- Crea la
MainWindow
la aplicación. Su constructor requiere unNoteCreator
. - OK, entonces crea un NoteCreator. Pero su constructor requiere un
IDocumentCreator
. - Mi configuración dice que para un
IDocumentCreator
, debería usarWordDocumentCreator
. Entonces crea unWordDocumentCreator
. - Ahora puedo pasar el
WordDocumentCreator
al NoteCreator. - Y ahora puedo pasar ese
NoteCreator
aMainWindow
.
La belleza de este sistema es triple.
Primero, si no configura algo, lo sabrá de inmediato, porque sus objetos se crean tan pronto como se ejecuta su aplicación. Ninject le enviará un mensaje de error útil que le IDocumentCreator
que su IDocumentCreator
(por ejemplo) no se puede resolver.
En segundo lugar, si la administración luego ordena al usuario de un procesador de texto superior, todo lo que tiene que hacer es
- Escriba un
WordPerfectDocumentCreator
que implementeIDocumentCreator
. - Cambie
MyAppModule
arriba, vinculandoIDocumentCreator
aWordPerfectDocumentCreator
lugar.
Tercero, si quiero probar mi NoteCreator
, no tengo que pasar un WordDocumentCreator
real (o lo que sea que esté usando). Puedo pasar uno falso . De esa forma puedo escribir una prueba que asume que mi IDocumentCreator
funciona correctamente, y solo prueba las partes móviles en NoteCreator
mismo. Mi falso IDocumentCreator
no hará más que devolver la respuesta correcta, y mi prueba se asegurará de que NoteCreator
haga lo correcto.
Para obtener más información acerca de cómo estructurar sus aplicaciones de esta manera, eche un vistazo al libro reciente de Mark Seemann, Dependency Injection en .NET . Desafortunadamente, no cubre Ninject, pero cubre una cantidad de otros marcos de DI, y habla sobre cómo estructurar su aplicación de la manera que he descrito anteriormente.
También eche un vistazo a Working Effectively With Legacy Code , de Michael Feathers. Él habla sobre el lado de las pruebas de lo anterior: cómo romper interfaces y pasar falsificaciones con el fin de aislar el comportamiento y someterlo a prueba.
No olvides que hay documentos, incluida una introducción que creo que sería muy apropiada dado el tipo de preguntas que estás haciendo en Ninject Wiki . Simplemente te molestas si intentas usar Ninject sin leerlo de principio a fin.
Pegue la tabla de contenidos en su barra de marcadores por un momento.
También puedo recomendar Injection de Dependency de Mark Seemann en .Net como un libro complementario para la arquitectura basada en DI (aunque no cubre directamente Ninject).