trabajar - programar por capas c#
Usando Nininject MVC con bibliotecas de clases (1)
Parece que tienes muchas preguntas sobre qué se debe responder aquí, así que intentaré dar lo mejor de mí.
Sobre la base de su pregunta actual, intentaré "elaborar" una arquitectura simplificada de su implementación actual:
- Capa de dominio: el núcleo de su dominio, el lugar de sus entidades comerciales, etc.
- Capa de infraestructura: aquí es donde residen sus servicios, por ejemplo:
WindowsHardwareService
- IOC : tiendo a llamar a esto como ensamblaje
DependencyResolution
.
- IOC : tiendo a llamar a esto como ensamblaje
- UI: aplicación MVC
Suponiendo que todo esto arriba, podemos afirmar que sus aplicaciones Composition Root
o Entry point
es el proyecto UI MVC. Uno de los conceptos principales que utiliza un DI Container
es que lo inicie en la configuración de la Composition Root
/ realice todos los enlaces y registros necesarios aquí. La intención principal de hacerlo en el punto de entrada es evitar el anti-patrón del Service Locator
.
Al usar un DI Container
usted no crea una new()
versión de sus implementaciones de clase ni obtiene el núcleo, sino que solicita la dependencia registrada, siguiendo la regla de Inversion Of Control
o también conocido como el principio de Hollywood.
Después del curso de filosofía, finalmente podemos llegar a alguna implementación real.
Creando un módulo Ninject : en su ensamblaje IOC , llamemos a este archivo como ServiceModule.cs
using Ninject.Modules;
public class ServiceModule : NinjectModule
{
public override void Load()
{
Bind<IHardwareService>().To<WindowsHardwareService>();
Bind<IStatusApi>().To<StatusApiController>();
}
}
Este será el Ninject module
que registrará / cargará en la Composition Root
.
Ahora sobre la raíz de la composición: en los proyectos de UI MVC NinjectWebCommon.cs
Puede tener un método que sea responsable de cargar sus módulos como se muestra a continuación.
private static void RegisterServices(IKernel kernel)
{
var modules = new List<INinjectModule>
{
new ServiceModule()
//, new FooModule()
//, new BarModule()
};
kernel.Load(modules);
}
Y finalmente su DashboardController
en UI MVC:
public class DashboardController : Controller
{
private readonly IHardwareService _hardwareService;
public DashboardController(IHardwareService hardwareService)
{
_hardwareService = hardwareService;
}
}
En este punto, solicite la implementación registrada de IHardwareService
en el constructor de controladores. El DI Container
hará el trabajo sucio y le pasará la instancia con la que puede trabajar más adelante en su controlador.
Una nota sobre las interfaces : tiendo a colocarlas en un ensamblaje propio, donde solo almaceno las interfaces, por ejemplo: Project.Domain.Interfaces
o Project.Infrastructure.Interfaces
donde cada uno de estos ensamblajes solo contiene interfaces de dominio o infraestructura.
Referencias entre asambleas:
Para juntar todo esto, la IU solo hace referencia al conjunto de IOC y al conjunto de interfaces que contiene las interfaces que ha enlazado en su Ninject Module
.
Resumiendo todo lo anterior:
Sus clases e interfaces solo son solo piezas que se pegan entre sí por el contenedor DI.
Espero haberlo aclarado un poco.
EDITAR: como un buen consejo que @AndreySarafanov señaló en los comentarios, si necesita diferentes implementaciones de una interfaz que solicite en el constructor, puede usar Ninject Factory . Para más información puedes consultar this respuesta.
Soy bastante nuevo en los marcos de IoC, así que disculpe la terminología.
Entonces, lo que tengo es un proyecto MVC con las referencias de Nininject MVC. Tengo otras bibliotecas de clase en mi proyecto, p. Ej., Capa de dominio. Me gustaría poder usar el marco de trabajo Ninject allí, pero todos mis enlaces están en NinjectWebCommon.cs
debajo de la carpeta App_Start
en el proyecto MVC:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IHardwareService>().To<WindowsHardwareService>();
kernel.Bind<IStatusApi>().To<StatusApiController>();
}
Actualmente, en la biblioteca de mi clase, estoy usando la inyección de constructor, pero a veces tengo que codificar las dependencias:
var service = new WindowsHardwareService();
Cuando me gustaría poder hacer lo siguiente:
IKernel kernel = new StandardKernel(.....);
var context = kernel.Get<IHardwareService>();
No he estado haciendo lo siguiente porque no tengo ningún módulo? Toda la documentación que he leído está dirigida principalmente a la biblioteca regular de Ninject y no a la versión MVC.
¿Qué debo hacer y cómo puedo usar la biblioteca regular de Ninject con la versión MVC?
Actualizar
Esto es lo que he intentado:
El objetivo de esto es que cada proyecto pueda cargar el módulo y obtener la interfaz inyectada actual.
App_Start / NinjectWebCommon.cs (en el proyecto MVC)
private static void RegisterServices(IKernel kernel)
{
var modules = new IoCModules();
var newKernal = modules.GetKernel();
kernel = newKernal;
}
IoCModules.cs (en el proyecto Project.Ioc)
public class IoCModules
{
public IKernel GetKernel()
{
var modules = new CoreModule();
return modules.Kernel;
}
}
CoreModule.cs (en Project.IoC.Modules project) <- Aquí es donde están todas las referencias a todos los proyectos, esto se trata de cualquier problema de dependencia circular.
public class CoreModule : NinjectModule
{
public override void Load()
{
Bind<IHardwareService>().To<WindowsHardwareService>();
Bind<IStatusApi>().To<StatusApiController>();
}
}
Pero actualmente estoy recibiendo lo siguiente:
Error al activar IHardwareService
No hay vinculaciones coincidentes disponibles, y el tipo no es auto-enlazable. Ruta de activación:
2) Inyección de la dependencia IHardwareService en el servicio de parámetros del constructor de tipo DashboardController
1) Solicitud de DashboardController
Sugerencias:
1) Asegúrese de haber definido un enlace para IHardwareService.
2) Si el enlace se definió en un módulo, asegúrese de que el módulo se haya cargado en el kernel.
3) Asegúrese de que no haya creado accidentalmente más de un kernel.
4) Si está utilizando argumentos de constructor, asegúrese de que el nombre del parámetro coincida con el nombre del parámetro del constructor.
5) Si está utilizando la carga automática de módulos, asegúrese de que la ruta de búsqueda y los filtros sean correctos.