Saltar al contenido
Implementación del patrón de repositorio en ASP.NET MVC aplicación

Implementación del patrón de repositorio en ASP.NET MVC aplicación

El patrón de repositorio es uno de los patrones más populares para crear una aplicación de nivel empresarial. Nos restringe el trabajo directo con los datos de la aplicación y crea nuevas capas para las operaciones de la base de datos, la lógica de negocios y la interfaz de usuario de la aplicación.

21min read

El patrón de repositorio es uno de los patrones más populares para crear una aplicación de nivel empresarial. Nos restringe el trabajo directo con los datos de la aplicación y crea nuevas capas para las operaciones de la base de datos, la lógica de negocios y la interfaz de usuario de la aplicación. Si una aplicación no sigue el patrón de repositorio, puede tener los siguientes problemas:

  • Códigos de operaciones de base de datos duplicados
  • Necesidad de interfaz de usuario para pruebas unitarias, operaciones de base de datos y lógica de negocios
  • Necesidad de dependencias externas para la lógica de negocios de pruebas unitarias
  • Difícil de implementar el almacenamiento en caché de la base de datos, etc.

El uso del patrón de repositorio tiene muchas ventajas:

  • Su lógica de negocio se puede probar unitariamente sin lógica de acceso a datos;
  • El código de acceso a la base de datos se puede reutilizar;
  • Su código de acceso a la base de datos se administra de forma centralizada, por lo que es fácil implementar cualquier política de acceso a la base de datos, como el almacenamiento en caché;
  • Es fácil implementar la lógica de dominio;
  • Las entidades de dominio o las entidades comerciales están fuertemente tipadas con anotaciones; y más.

En Internet, hay millones de artículos escritos en torno al Patrón de Repositorio, pero en este, nos vamos a centrar en cómo implementarlo en una aplicación ASP.NET MVC. ¡Así que comencemos!

Antes de seguir adelante y aprender sobre el patrón de repositorio en ASP.NET MVC, le recomiendo que consulte Infragistics biblioteca basada en jQuery Ignite UI, que lo ayuda a escribir y ejecutar aplicaciones web más rápido. Puede utilizar la biblioteca Ignite UI para JavaScript para ayudar a resolver rápidamente requisitos complejos de LOB en HTML5, jQuery, Angular, React o ASP.NET MVC. (Puedes descargar una versión de prueba gratuita de Ignite UI aquí).

Estructura del proyecto

Comencemos con la creación de la estructura del proyecto para la aplicación. Vamos a crear cuatro proyectos:

  1. Proyecto Principal
  2. Proyecto de Infraestructura
  3. Proyecto de prueba
  4. MVC Project

Cada proyecto tiene su propio propósito. Probablemente pueda adivinar por los nombres de los proyectos lo que contendrán: los proyectos principales y de infraestructura son bibliotecas de clases, el proyecto web es un proyecto MVC y el proyecto de prueba es un proyecto de prueba unitaria. Eventualmente, los proyectos en el explorador de soluciones tendrán el aspecto que se muestra en la imagen a continuación:

 Web project is an MVC

A medida que avancemos en este post, conoceremos en detalle sobre el propósito de cada proyecto, sin embargo, para comenzar podemos resumir el objetivo principal de cada proyecto de la siguiente manera:

La comprensión de los diferentes proyectos es clara

Hasta ahora, nuestra comprensión de los diferentes proyectos es clara. Ahora sigamos adelante e implementemos cada proyecto uno por uno. Durante las implementaciones, exploraremos en detalle las responsabilidades de cada proyecto.

Proyecto Principal

En el proyecto principal, mantenemos las entidades y las interfaces de repositorio o las interfaces de operación de la base de datos. El proyecto principal contiene información sobre las entidades de dominio y las operaciones de base de datos necesarias en las entidades de dominio. En un escenario ideal, el proyecto principal no debería tener ninguna dependencia de bibliotecas externas. No debe tener ninguna lógica de negocio, códigos de operación de base de datos, etc.

En resumen, el proyecto principal debe contener:

  • Entidades de dominio
  • Interfaces de repositorio o interfaces de operaciones de base de datos en entidades de dominio
  • Anotaciones de datos específicas del dominio

El proyecto principal NO puede contener:

  • Cualquier biblioteca externa para operaciones de base de datos
  • Business logic
  • Código de operaciones de base de datos

Al crear las entidades de dominio, también debemos tomar una decisión sobre las restricciones en las propiedades de las entidades de dominio, por ejemplo:

  • Si se requiere una propiedad en particular o no. Por ejemplo, para una entidad Product, el nombre del producto debe ser propiedad required.
  • Si un valor de una propiedad en particular está en un rango determinado o no. Por ejemplo, para una entidad Product, la propiedad price debe estar en un rango determinado.
  • Si no se debe dar valor a la longitud máxima de una propiedad determinada. Por ejemplo, para una entidad Product, el valor de la propiedad name debe ser menor que la longitud máxima.

Podría haber muchas anotaciones de datos de este tipo en las propiedades de las entidades de dominio. Hay dos maneras en las que podemos pensar en estas anotaciones de datos:

  1. Como parte de las entidades de dominio
  2. Como parte de la lógica de operaciones de base de datos

Depende exclusivamente de nosotros cómo vemos las anotaciones de datos. Si los consideramos parte de la operación de la base de datos, podemos aplicar restricciones utilizando la API de bibliotecas de operaciones de la base de datos. Vamos a usar Entity Framework para las operaciones de base de datos en el proyecto de infraestructura, por lo que podemos usar la API fluida de Entity Framework para anotar datos.

Si los consideramos parte del dominio, entonces podemos usar la biblioteca System.ComponentModel.DataAnnotations para anotar los datos. Para usar esto, haga clic derecho en la carpeta de referencia del proyecto principal y haga clic en Agregar referencia. En la pestaña Marco, seleccione System.ComponentModel.DataAnnotations y agréguelo al proyecto.

Estamos creando una ProductApp, así que comencemos con la creación de la entidad Product. Para agregar una clase de entidad, haga clic con el botón derecho en el proyecto principal y agregue una clase, luego asigne a la clase el nombre Product.

using System.ComponentModel.DataAnnotations;
namespace ProductApp.Core
{
    public class Product
    {
        public int Id { get; set; }
 [Required]
 [MaxLength(100)]
        public string Name { get; set; }
 [Required]
        public double Price { get; set; }
        public bool inStock { get; set; }
    }
}

Hemos anotado las propiedades de la entidad Product con Required y MaxLength. Ambas anotaciones forman parte de System.ComponentModel.DataAnnotations. Aquí, hemos considerado la restricción como parte del dominio, por lo tanto, hemos utilizado anotaciones de datos en el proyecto principal en sí.

Hemos creado la clase Product Entity y también le hemos aplicado la anotación de datos. Ahora sigamos adelante y creemos la interfaz del repositorio. Pero antes de crear eso, entendamos, ¿qué es una interfaz de repositorio?

La interfaz del repositorio define todas las operaciones de base de datos posibles en las entidades de dominio. Todas las operaciones de la base de datos que se pueden realizar en las entidades del dominio son parte de la información del dominio, por lo tanto, pondremos la interfaz del repositorio en el proyecto principal. La forma en que se pueden realizar estas operaciones será parte del proyecto de infraestructura.

Para crear una interfaz de repositorio, haga clic con el botón derecho en el proyecto principal y agregue una carpeta llamada Interfaces. Una vez creada la carpeta Interfaces, haga clic con el botón derecho en la carpeta Interface y seleccione agregar un nuevo elemento, luego, en la pestaña Código, seleccione Interfaz. Asigne a la interfaz el nombre IProductRepository

using System.Collections.Generic;

namespace ProductApp.Core.Interfaces
{
    public interface IProductRepository
    {
        void Add(Product p);
        void Edit(Product p);
        void Remove(int Id);
        IEnumerable GetProducts(); Product FindById(int Id); 
    } 
} 

Ahora hemos creado una clase de entidad Product y una interfaz de repositorio de productos. En este punto, el proyecto principal debería verse así:

 solution tree

Sigamos adelante y construyamos el proyecto principal para verificar que todo esté en su lugar y avancemos para crear un proyecto de infraestructura.

Proyecto de Infraestructura

El objetivo principal del proyecto de infraestructura es realizar operaciones de base de datos. Además de las operaciones de base de datos, también puede consumir servicios web, realizar operaciones de E/S, etc. Por lo tanto, principalmente, el proyecto de infraestructura puede realizar las siguientes operaciones:

  • Database operations
  • Trabajar con WCF y servicios web
  • IO operations

Podemos utilizar cualquier tecnología de base de datos para realizar operaciones de base de datos. En esta publicación, vamos a usar Entity Framework. Así que vamos a crear una base de datos utilizando el enfoque Code First. En el enfoque Code First, la base de datos se crea en función de las clases. Aquí, la base de datos se creará sobre la base de las entidades de dominio del proyecto principal.

Para crear la base de datos a partir de la entidad de dominio del proyecto principal, debemos realizar estas tareas:

  1. Create DataContext class
  2. Configurar la cadena de conexión
  3. Creación de una clase de inicializador de base de datos para inicializar datos en la base de datos
  4. Implementación de la interfaz IProductRepsitory

 

Adición de referencias

En primer lugar, agreguemos referencias al proyecto Entity Framework y ProductApp.Core. Para agregar Entity Framework, haga clic con el botón derecho en el proyecto de infraestructura y haga clic en Administrar paquete Nuget. En la ventana Administrador de paquetes, busque Entity Framework e instale la versión estable más reciente.

Para agregar una referencia del proyecto ProductApp.Core, haga clic con el botón derecho en el proyecto Infraestructura y haga clic en Agregar referencia. En la ventana de referencia, haga clic en la pestaña Proyecto y seleccione ProductApp.Core.

DataContext class

El objetivo de la clase DataContext es crear la base de datos en el enfoque Code First de Entity Framework. Pasamos una cadena de conexión en el constructor de la clase DataContext. Al leer la cadena de conexión, Entity Framework crea la base de datos. Si no se especifica una cadena de conexión, Entity Framework crea la base de datos en un servidor de base de datos local.

In the DataContext class:

  • Cree una propiedad de tipo DbSet. Esto es responsable de crear la tabla para la entidad Product
  • En el constructor de la clase DataContext, pase la cadena de conexión para especificar la información necesaria para crear una base de datos, por ejemplo, el nombre del servidor, el nombre de la base de datos, la información de inicio de sesión, etc. Necesitamos pasar el nombre de la cadena de conexión. Nombre donde se crearía la base de datos
  • Si no se pasa la cadena de conexión, Entity Framework crea con el nombre de la clase de contexto de datos en el servidor de base de datos local.
  • La clase productdatacontext hereda la clase DbContext

La clase ProductDataContext se puede crear como se muestra en la lista siguiente:

using ProductApp.Core;
using System.Data.Entity;

namespace ProductApp.Infrastructure
{
    public class ProductContext  : DbContext
    {
        public ProductContext()  : base("name=ProductAppConnectionString") {}
        public DbSet Products { get; set; }
    }
} 

A continuación, tenemos que trabajar en la cadena de conexión. Como se explicó anteriormente, podemos pasar la cadena de conexión para especificar la información de creación de la base de datos o responder en Entity Framework para crear una base de datos predeterminada en la ubicación predeterminada para nosotros. Vamos a especificar la cadena de conexión, por eso pasamos un nombre de cadena de conexión ProductAppConnectionString en el constructor de la clase ProductDataContext. En el archivo App.Config, se puede crear la cadena de conexión ProductAppConnectionString, como se muestra en la lista siguiente:

 <add name="ProductAppConnectionString" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=ProductAppJan;Integrated Security=True;MultipleActiveResultSets=true" providerName="System.Data.SqlClient"/>

Clase inicializadora de base de datos

Creamos una clase inicializadora de base de datos para inicializar la base de datos con algún valor inicial en el momento de la creación. Para crear la clase inicializadora de base de datos, cree una clase que herede de DropCreateDatabaseIfModelChnages. Hay otras opciones de clases disponibles para heredar con el fin de crear una clase de inicializador de base de datos. Si heredamos la clase DropCreateDatabaseIfModelChnages, cada vez que se cree una nueva base de datos en el modelo cambia. Así, por ejemplo, si agregamos o quitamos propiedades de la clase de entidad Product, Entity Framework quitará la base de datos existente y creará una nueva. Por supuesto, esta no es una gran opción, ya que los datos también se perderán, por lo que le recomiendo que explore otras opciones para heredar la clase inicializadora de la base de datos.

La clase inicializadora de base de datos se puede crear como se muestra en la lista a continuación. Aquí estamos sembrando la tabla de productos con dos filas. Para inicializar los datos:

  1. Override Seed method
  2. Añadir producto a Context.Products
  3. Llame a Context.SaveChanges()
using ProductApp.Core;
using System.Data.Entity;

namespace ProductApp.Infrastructure {
  public class ProductInitalizeDB : DropCreateDatabaseIfModelChanges {
    protected override void Seed(ProductContext context) {
      context.Products.Add(
          new Product { Id = 1, Name = "Rice", inStock = true, Price = 30 });
      context.Products.Add(
          new Product { Id = 2, Name = "Sugar", inStock = false, Price = 40 });
      context.SaveChanges();
      base.Seed(context);
    }
  }
}

Hasta ahora, hemos realizado todo el trabajo relacionado con Code First de Entity Framework para crear la base de datos. Ahora vamos a seguir adelante e implementar una interfaz IProductRepository del proyecto Core en una clase ProductRepository concreta.

Repository Class

Esta es la clase que realizará las operaciones de base de datos en la entidad del producto. En esta clase, implementaremos la interfaz IProductRepository del proyecto Core. Comencemos agregando una clase ProductRepository al proyecto Infrastructure e implementemos la interfaz IProductRepository. Para realizar operaciones de base de datos, vamos a escribir consultas sencillas de LINQ to Entity. La clase de repositorio de productos se puede crear como se muestra en la lista a continuación:

using ProductApp.Core.Interfaces;
using System.Collections.Generic;
using System.Linq;
using ProductApp.Core;

namespace ProductApp.Infrastructure {
  public class ProductRepository : IProductRepository {
    ProductContext context = new ProductContext();
    public void Add(Product p) {
      context.Products.Add(p);
      context.SaveChanges();
    }

    public void Edit(Product p) {
      context.Entry(p).State = System.Data.Entity.EntityState.Modified;
    }

    public Product FindById(int Id) {
            var result = (from r in context.Products where r.Id == Id select r).FirstOrDefault();
            return result;
    }

    public IEnumerable GetProducts() {
      return context.Products;
    }
    public void Remove(int Id) {
      Product p = context.Products.Find(Id);
      context.Products.Remove(p);
      context.SaveChanges();
    }
  }
}

Hasta ahora hemos creado una clase Data Context, una clase Database Initializer y la clase Repository. Construyamos el proyecto de infraestructura para asegurarnos de que todo esté en su lugar. El proyecto ProductApp.Infrastructure tendrá el aspecto que se muestra en la siguiente imagen:

Ahora hemos terminado de crear el proyecto de infraestructura. Hemos escrito todas las clases relacionadas con las operaciones de la base de datos dentro del proyecto de infraestructura, y toda la lógica relacionada con la base de datos está en un lugar central. Siempre que se requieran cambios en la lógica de la base de datos, solo debemos cambiar el proyecto de infraestructura.

Proyecto de prueba

La mayor ventaja de Repository Pattern es la capacidad de prueba. Esto nos permite realizar pruebas unitarias de los distintos componentes sin tener dependencias de otros componentes del proyecto. Por ejemplo, hemos creado la clase Repository que realiza las operaciones de la base de datos para verificar la corrección de la funcionalidad, por lo que debemos hacer una prueba unitaria. También deberíamos poder escribir pruebas para la clase Repository sin ninguna dependencia del proyecto web o la interfaz de usuario. Dado que estamos siguiendo el patrón de repositorio, podemos escribir pruebas unitarias para el proyecto de infraestructura sin ninguna dependencia del proyecto MVC (UI).

Para escribir pruebas unitarias para la clase ProductRepository, agreguemos las siguientes referencias en el proyecto de prueba.

  1. Referencia del proyecto ProductApp.Core
  2. Referencia del proyecto ProductApp.Infrastructure
  3. Entity Framework package

Para agregar Entity Framework, haga clic con el botón derecho en el proyecto de prueba y haga clic en Administrar paquete Nuget. En el Administrador de paquetes de Windows, busque Entity Framework e instale la versión estable más reciente.

Para agregar una referencia del proyecto ProductApp.Core, haga clic con el botón derecho en el proyecto de prueba y haga clic en Agregar referencia. En la ventana de referencia, haga clic en la pestaña Proyecto y seleccione ProductApp.Core.

Para agregar una referencia del proyecto ProductApp.Infrastructure, haga clic con el botón derecho en el proyecto de prueba y haga clic en Agregar referencia. En la ventana de referencia, haga clic en la pestaña Proyecto y seleccione ProductApp.Infrastructure.

Copie la cadena de conexión

Visual Studio siempre lee el archivo de configuración del proyecto en ejecución. Para probar el proyecto de infraestructura, ejecutaremos el proyecto de prueba. Por lo tanto, la cadena de conexión debe formar parte de App.Config del proyecto de prueba. Vamos a copiar y pegar la cadena de conexión del proyecto de infraestructura en el proyecto de prueba.

Hemos agregado todas las referencias requeridas y copiado la cadena de conexión. Sigamos adelante ahora y configuremos la clase de prueba. Crearemos una clase de prueba con el nombre ProductRepositoryTest. Test Initialize es la función que se ejecuta antes de que se ejecuten las pruebas. Necesitamos crear una instancia de la clase ProductRepository y llamar a la clase ProductDbInitalize para inicializar los datos antes de ejecutar las pruebas. El inicializador de prueba se puede escribir como se muestra en la lista a continuación:

[TestClass]
public class ProductRepositoryTest {
  ProductRepository Repo;
  [TestInitialize]
  public void TestSetup() {
    ProductInitalizeDB db = new ProductInitalizeDB();
    System.Data.Entity.Database.SetInitializer(db);
    Repo = new ProductRepository();
  }
}

Ahora hemos escrito el inicializador de prueba. Ahora vamos a escribir la primera prueba para comprobar si la clase ProductInitalizeDB inicializa dos filas en la tabla Product o no. Dado que es la primera prueba que ejecutaremos, también verificará si la base de datos se crea o no. Así que, esencialmente, estamos escribiendo una prueba:

  1. Para verificar la creación de la base de datos
  2. Para comprobar el número de filas insertadas por el método de inicialización del inicializador de base de datos de productos
[TestMethod]
public void IsRepositoryInitalizeWithValidNumberOfData() {
  var result = Repo.GetProducts();
  Assert.IsNotNull(result);
  var numberOfRecords = result.ToList().Count;
  Assert.AreEqual(2, numberOfRecords);
}

Como puedes ver, estamos llamando a la función GetProducts() del repositorio para obtener todos los productos insertados al crear la base de datos. Esta prueba verifica realmente si GetProducts() funciona como se esperaba o no, y también verifica la creación de la base de datos. En la ventana del Explorador de pruebas, podemos ejecutar la prueba para su verificación.

llamando a la función GetProducts() del repositorio para obtener todos los productos

Para ejecutar la prueba, primero compile el proyecto de prueba y, a continuación, en el menú superior, seleccione Test->Windows-Test Explorer. En el Explorador de pruebas, encontraremos todas las pruebas enumeradas. Seleccione la prueba y haga clic en Ejecutar.

Sigamos adelante y escribamos una prueba más para verificar la operación Agregar producto en el repositorio:

[TestMethod]
public void IsRepositoryAddsProduct() {
  Product productToInsert =
      new Product { Id = 3, inStock = true, Name = "Salt", Price = 17

      };
  Repo.Add(productToInsert);
  // If Product inserts successfully,
  // number of records will increase to 3
  var result = Repo.GetProducts();
  var numberOfRecords = result.ToList().Count;
  Assert.AreEqual(3, numberOfRecords);
}

Para verificar la inserción del producto, llamamos a la función Agregar en el repositorio. Si el producto se agrega correctamente, el número de registros aumentará de 2 a 3 y lo estamos verificando. Al ejecutar la prueba, encontraremos que la prueba ha sido superada.

De esta manera, podemos escribir pruebas para todas las operaciones de la base de datos desde la clase Product Repository. Ahora estamos seguros de que hemos implementado la clase Repository correctamente porque las pruebas se están superando, lo que significa que el proyecto Infrastructure and Core se puede usar con cualquier proyecto de interfaz de usuario (en este caso, MVC).

MVC o Proyecto Web

¡Finalmente, hemos llegado al proyecto MVC! Al igual que el proyecto de prueba, debemos agregar las siguientes referencias

  1. Referencia del proyecto ProductApp.Core
  2. Referencia del proyecto ProductApp.Infrastructure

Para agregar una referencia del proyecto ProductApp.Core, haga clic con el botón derecho en el proyecto MVC y haga clic en Agregar referencia. En la ventana de referencia, haga clic en la pestaña Proyecto y seleccione ProductApp.Core.

Para agregar una referencia del proyecto ProductApp.Infrastructure, haga clic con el botón derecho en el proyecto MVC y haga clic en Agregar referencia. En la ventana de referencia, haga clic en la pestaña Proyecto y seleccione ProductApp.Infrastructure.

Copie la cadena de conexión

Visual Studio siempre lee el archivo de configuración del proyecto en ejecución. Para probar el proyecto de infraestructura, ejecutaremos el proyecto de prueba, por lo que la cadena de conexión debe formar parte de la App.Config del proyecto de prueba. Para hacerlo más fácil, copiemos y peguemos la cadena de conexión del proyecto de infraestructura en el proyecto de prueba.

Andamiaje de la aplicación

Deberíamos tener todo en su lugar para andamiar el controlador MVC. Para aplicar scaffolding, haga clic con el botón derecho en la carpeta Controller y seleccione MVC 5 Controller with Views, using Entity Framework como se muestra en la imagen siguiente:

Andamiaje de la aplicación

A continuación, veremos la ventana Agregar controlador. Aquí tenemos que proporcionar la clase de modelo y la información de la clase de contexto de datos. En nuestro proyecto, la clase de modelo es la clase Product del proyecto principal y la clase de contexto de datos es la clase ProductDataContext del proyecto de infraestructura. Seleccionemos ambas clases del menú desplegable como se muestra en la imagen a continuación:

Aquí tenemos que proporcionar la clase de modelo y la información de la clase de contexto de datos

Además, debemos asegurarnos de que las opciones Generar vistas, Bibliotecas de scripts de referencia y Usar una página de diseño estén seleccionadas.

Al hacer clic en Agregar, Visual Studio creará el ProductsController y Views dentro de la carpeta Views/Products. El proyecto MVC debe tener la estructura que se muestra en la imagen a continuación:

Visual Studio creará el ProductsController y Views dentro de la carpeta Views/Products

En este punto, si seguimos adelante y ejecutamos la aplicación, podremos realizar operaciones CRUD en la entidad Product.

  go ahead and run the application,

Problema con los andamios

¡Pero aún no hemos terminado! Abramos la clase ProductsController y examinemos el código. En la primera línea, encontraremos el problema. Dado que hemos usado el scaffolding de MVC, MVC está creando un objeto de la clase ProductContext para realizar las operaciones de base de datos.

Las dependencias de la clase de contexto enlazan estrechamente el proyecto de interfaz de usuario y la base de datos entre sí. Como sabemos, la clase Datacontext es un componente de Entity Framework. No queremos que el proyecto MVC sepa qué tecnología de base de datos se está utilizando en el proyecto de infraestructura. Por otro lado, no hemos probado la clase Datacontext; hemos probado la clase ProductRepository. Idealmente, deberíamos usar la clase ProductRepository en lugar de la clase ProductContext para realizar operaciones de base de datos en el controlador MVC.  En resumen,

  1. MVC Scaffolding usa la clase de contexto de datos para realizar operaciones de base de datos. La clase de contexto de datos es un componente de Entity Framework, por lo que su uso acopla estrechamente la interfaz de usuario (MVC) con la tecnología de base de datos (EF).
  2. La clase de contexto de datos no se ha probado unitariamente, por lo que no es una buena idea usarla.
  3. Tenemos una clase ProductRepository probada. Debemos usar esto dentro del controlador para realizar operaciones de base de datos. Además, la clase ProductRepository no expone la tecnología de base de datos a la interfaz de usuario.

Para usar la clase ProductRepository para las operaciones de base de datos, es necesario refactorizar la clase ProductsController. Para ello, hay dos pasos que debemos seguir:

  1. Cree un objeto de la clase ProductRepository en lugar de la clase ProductContext.
  2. Llame a los métodos de la clase ProductRepository para realizar operaciones de base de datos en la entidad Product en lugar de los métodos de la clase ProductContext.

En la lista a continuación, he comentado códigos usando ProductContext y llamé a los métodos ProductRepository. Después de la refactorización, la clase ProductController tendrá el siguiente aspecto:

using System;
using System.Net;
using System.Web.Mvc;
using ProductApp.Core;
using ProductApp.Infrastructure;

namespace ProductApp.Web.Controllers {
  public class ProductsController : Controller {
    // private ProductContext db = new ProductContext();
    private ProductRepository db = new ProductRepository();

    public ActionResult Index() {
      // return View(db.Products.ToList());
      return View(db.GetProducts());
    }

    public ActionResult Details(int? id) {
      if (id == null) {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
      }
      // Product product = db.Products.Find(id);
      Product product = db.FindById(Convert.ToInt32(id));
      if (product == null) {
        return HttpNotFound();
      }
      return View(product);
    }

    public ActionResult Create() {
      return View();
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create(
        [Bind(Include = "Id,Name,Price,inStock")] Product product) {
      if (ModelState.IsValid) {
        // db.Products.Add(product);
        // db.SaveChanges();
        db.Add(product);
        return RedirectToAction("Index");
      }

      return View(product);
    }

    public ActionResult Edit(int? id) {
      if (id == null) {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
      }
      Product product = db.FindById(Convert.ToInt32(id));
      if (product == null) {
        return HttpNotFound();
      }
      return View(product);
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit(
        [Bind(Include = "Id,Name,Price,inStock")] Product product) {
      if (ModelState.IsValid) {
        // db.Entry(product).State = EntityState.Modified;
        // db.SaveChanges();
        db.Edit(product);
        return RedirectToAction("Index");
      }
      return View(product);
    }

    public ActionResult Delete(int? id) {
      if (id == null) {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
      }
      Product product = db.FindById(Convert.ToInt32(id));
      if (product == null) {
        return HttpNotFound();
      }
      return View(product);
    }

    [HttpPost, ActionName("Delete")]
    [ValidateAntiForgeryToken]
    public ActionResult DeleteConfirmed(int id) {
      // Product product = db.FindById(Convert.ToInt32(id));
      //  db.Products.Remove(product);
      //  db.SaveChanges();
      db.Remove(id);
      return RedirectToAction("Index");
    }

    protected override void Dispose(bool disposing) {
      if (disposing) {
        // db.Dispose();
      }
      base.Dispose(disposing);
    }
  }
}

Después de la refactorización, sigamos adelante y construyamos y ejecutemos la aplicación: deberíamos poder hacerlo y realizar las operaciones CRUD.

Inyección de la dependencia

Ahora estamos contentos de que la aplicación esté en funcionamiento y se haya creado con el patrón Repository. Pero todavía hay un problema: estamos creando directamente un objeto de la clase ProductRepository dentro de la clase ProductsController, y no queremos esto. Queremos invertir la dependencia y delegar la tarea de inyectar la dependencia a un tercero, conocido popularmente como contenedor DI. Básicamente, ProductsController pedirá al contenedor de inserción de dependencias que devuelva la instancia de IProductRepository.

Hay muchos contenedores DI disponibles para aplicaciones MVC. En este ejemplo, usaremos el contenedor de DI de Unity más sencillo. Para ello, haga clic con el botón derecho en el proyecto MVC y haga clic en Administrar paquete Nuget. En el Administrador de paquetes NuGet, busque Unity.Mvc e instale el paquete.

Administración del paquete Nuget

Una vez instalado el paquete Unity.Mvc, vamos a abrir una carpeta App_Start. Dentro de la carpeta App_Start, encontraremos el archivo UnityConfig.cs. En la clase UnityConfig, tenemos que registrar el tipo. Para hacerlo, abra la función RegisterTypes en la clase UnityConfig y registre el tipo como se muestra en la lista a continuación:

public static void RegisterTypes(IUnityContainer container) {
  // TODO: Register your types here
  container.RegisterType<iproductrepository, productrepository = "">();
}

Hemos registrado el tipo en el contenedor Unity DI. Ahora sigamos adelante y hagamos un poco de refactorización en la clase ProductsController.  En el constructor de ProductsController, pasaremos la referencia a la interfaz del repositorio. Siempre que la aplicación lo requiera, el contenedor de DI de Unity insertará el objeto concreto de ProductRepository en la aplicación resolviendo el tipo. Necesitamos refactorizar el ProductsController como se muestra en la lista a continuación:

public class ProductsController : Controller {
  IProductRepository db;
  public ProductsController(IProductRepository db) {
    this.db = db;
  }

Sigamos adelante y construyamos y ejecutemos la aplicación. Deberíamos tener la aplicación en funcionamiento, y deberíamos ser capaces de realizar operaciones CRUD utilizando el patrón de repositorio y la inyección de dependencias.

Conclusión

En este artículo, aprendimos paso a paso cómo crear una aplicación MVC siguiendo el patrón Repository. Al hacerlo, podemos poner toda la lógica de la base de datos en un solo lugar y, cuando sea necesario, solo necesitamos cambiar el repositorio y probarlo. El patrón de repositorio también acopla de forma flexible la interfaz de usuario de la aplicación con la lógica de la base de datos y las entidades de dominio, lo que hace que la aplicación sea más comprobable.

Además, no olvide consultar Ignite UI, que puede usar con HTML5, Angular, React o ASP.NET MVC para crear aplicaciones de Internet enriquecidas. ¡Gracias por leer!

Solicitar una demostración