Entonces, ¿cómo entran en juego las interfaces?
De esta manera:
public interface IEmployeeRepository
{
Employee[] GetAll();
}
y entonces usted podría tener tantas implementaciones como desee:
public class EmployeeRepositoryEF: IEmployeeRepository
{
public Employee[] GetAll()
{
//here you will return employees after querying your EF DbContext
}
}
public class EmployeeRepositoryXML: IEmployeeRepository
{
public Employee[] GetAll()
{
//here you will return employees after querying an XML file
}
}
public class EmployeeRepositoryWCF: IEmployeeRepository
{
public Employee[] GetAll()
{
//here you will return employees after querying some remote WCF service
}
}
and so on ... you could have as many implementation as you like
Como se puede ver que no es realmente importante cómo ponemos en práctica el repositorio.Lo importante es que todos los repositorios y las implementaciones respetan el contrato definido (interfaz) y todos poseen un método GetAll
que devuelve una lista de empleados.
Y luego tendrá un controlador que utiliza esta interfaz.
public class EmployeesController: Controller
{
private readonly IEmployeeRepository _repository;
public EmployeesController(IEmployeeRepository repository)
{
_repository = repository;
}
public ActionResult Index()
{
var employees = _repository.GetAll();
return View(employees);
}
}
Vea cómo el controlador ya no depende de una implementación específica del repositorio? Todo lo que necesita saber es que esta implementación respeta el contrato. Ahora todo lo que necesita hacer es configurar su marco de inyección de dependencias favorito para usar la implementación que desee.
Aquí hay un ejemplo de cómo se hace esto con Ninject:
- Instalar el Ninject.MVC3 NuGet
En el ~/App_Start/NinjectWebCommon.cs
código generado simplemente decide utilizar la aplicación EF con una sola línea de código:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IEmployeeRepository>().To<EmployeeRepositoryEF>();
}
de esta manera ya no es necesario hacer ningún ejemplificaciones de manuales esas clases de repositorio y se preocupan por upcasting o lo que sea. Es el marco de inyección de dependencias que los administra por usted y se encargará de inyectar la implementación definida en el constructor del controlador.
Y simplemente modificando esta configuración, puede cambiar su tecnología de acceso a datos sin tocar una sola línea de código en su controlador. Así es como entran en juego las pruebas unitarias en aislamiento. Dado que su código de controlador ahora está débilmente acoplado al repositorio (gracias a la interfaz que presentamos), todo lo que necesita hacer en la prueba unitaria es proporcionar alguna implementación simulada en el repositorio que le permita definir su comportamiento. Esto le da la posibilidad de probar la unidad de la acción del controlador de índice sin ninguna dependencia en una base de datos o lo que sea. Aislamiento completo
También lo invito a que compruebe el following articles sobre TDD y DI en ASP.NET MVC.
maravillosa respuesta, cada explicación vale ... ahora lo entiendo cómo funcionan las cosas ... gracias, no puedo marcar esta respuesta como aceptada ya que mis puntos están por debajo de 15, tan pronto como gane lo aceptaré como respuesta. – Meson
gracias por ese artículo ... y supongamos que si configuro 'EmployeeRepositoryEF' en mi marco de inyección de dependencias, mi controlador consumirá este' EmployeeRepositoryEF', pero ¿y si quiero consumir 2 implementaciones en el mismo controlador ... si esta pregunta es estúpida? lo siento mucho ... – Meson
En el ejemplo I provider, el controlador espera una instancia 'IEmployeeRepository' en su constructor. Solo se puede aprobar una implementación única. Por otro lado, podría tener otro controlador que pueda necesitar una implementación diferente de la interfaz. Eso es perfectamente posible. Solo necesita configurar su infraestructura DI para que inyecte ImplementationA en ControllerA e ImplementationB en ControllerB. La sintaxis, por supuesto, variará entre los diferentes marcos DI. –