net mvc migrations framework con asp and asp.net-mvc entity-framework inversion-of-control castle-windsor

asp.net-mvc - migrations - mvc crud entity framework



Usando Entity Framework con Castle Windsor (1)

Utilizo el primer enfoque de la base de datos de Entity Framework para generar un modelo DbContext / POCO para una aplicación MVC. Quiero evitar tener dependencias de DbContext en mis controladores para que pueda cambiarme a otro proveedor de persistencia cuando sea necesario (por ejemplo, con fines de prueba de unidad).

Para hacer esto quiero usar el contenedor de IoC de Castle Windsor. Planeo registrar DbContext como un servicio IUnitOfWork y registrar un servicio genérico de IRepository, implementaciones de las cuales usaré para acceder y trabajar con raíces agregadas en el modelo.

Soy nuevo en Windsor y no he podido encontrar mucha información sobre su uso con EF, y tengo un par de preguntas:

  • ¿Es este un enfoque razonable si quiero desacoplar EF de la aplicación?
  • ¿Cómo instalo / registro los servicios IUnitOfWork e IRepository genéricos?

Entonces, algunas conclusiones. Pensé que escribiría esto en caso de que sea de utilidad para otra persona que intente usar / probar la unidad EF, Windsor y MVC juntos.

En primer lugar, como DbContext implementa los patrones de Repositorio y Unidad de trabajo, debe tener en cuenta si estas implementaciones servirán o si necesita crear las suyas propias.

Elegí crear mi propio Repositorio, siguiendo el patrón DDD: uno por raíz agregada. Los motivos: para encapsular el código de consulta, evitar que se filtre en la capa de aplicación y poder simularse más fácilmente al probar los controladores de la aplicación. IRepository<TEntity> un repositorio genérico basado en IRepository<TEntity> . Hay muchos ejemplos por ahí. Me pareció una buena: http://architects.dzone.com/articles/implementing-repository

Por otro lado, decidí abandonar el servicio IUnitOfWork, optando por la implementación predeterminada en su lugar. Sin embargo, creé una abstracción IDbContext (no sé por qué Microsoft no hizo esto por sí misma), para poder burlarme de DbContext al probar los servicios del Repositorio.

Le di a IDbContext solo los miembros de DbContext que quería usar en el repositorio. Asi que:

public interface IDbContext: IDisposable { Database Database { get; } DbEntityEntry Entry(object entity); IDbSet<TEntity> Set<TEntity>() where TEntity : class; int SaveChanges(); }

Luego creé una instalación e instalador de Windsor para mis servicios IDbContext e IRepository:

public class EntityFrameworkFacility: AbstractFacility { protected override void Init() { Kernel.Register(Component.For<IDbContext>() .ImplementedBy<MyEntities>() .LifestylePerWebRequest(), Component.For(typeof(IRepository<>)) .ImplementedBy(typeof(Repository<>)) .LifestylePerWebRequest()); } } public class PersistenceInstaller : IWindsorInstaller { public void Install(IWindsorContainer container, IConfigurationStore store) { container.AddFacility<EntityFrameworkFacility>(); } }

La última pieza fue ampliar la clase de contexto de Entity Framework para implementar IDbContext y sombrear el método Set () para devolver IDbSet en lugar de DbSet:

public partial class MyEntities : IDbContext { public new IDbSet<TEntity> Set<TEntity>() where TEntity : class { return base.Set<TEntity>(); } }

Con todo esto en su lugar (y el registro de ControllerFactory ilustrado en los documentos de Windsor), resulta trivial hacer que Windsor inyecte objetos de IRepository (o IDbContext) en los constructores de controladores, según sea necesario:

public ControllerBase(IRepository<Contact> repo) { _repo = repo; }

En las pruebas unitarias del repositorio, una instancia de repositorio real se puede respaldar con un IDbContext simulado:

mocks = new MockRepository(); context = mocks.StrictMock<IDbContext>(); repo = new Repository<Contact>(context);

En las pruebas unitarias del controlador, se puede usar un repositorio simulado:

mocks = new MockRepository(); repo = mocks.StrictMock<IRepository<Contact>>(); ContactController controller = new ContactController(repo);