Patrón MVC
Cómo ordenar el back-end de una aplicación web con Modelo, Vista y Controlador
Un cambio de precio que rompió la facturación
con SQL, HTML y reglas de negocio mezclados en la misma página
para encontrar por qué la factura cobraba un 10 % de más
@{
var cn = new SqlConnection("Server=...");
var lista = cn.Query("SELECT * FROM Productos");
foreach (var p in lista)
{
if (p.Stock < 5) p.Precio *= 1.10m; // ¿regla?
<tr><td>@p.Nombre</td>
<td>@p.Precio</td></tr>
}
}
MVC: tres responsabilidades, tres lugares
Modelo
Los datos y las reglas del negocio
- Clases como Producto, Venta o Cliente
- Valida y calcula; no sabe nada de HTML
Vista
Lo que ve el usuario
- Plantillas Razor (.cshtml)
- Muestra datos; nunca consulta la base de datos
Controlador
El que coordina
- Recibe la petición y decide qué responder
- Pide datos al modelo y se los entrega a la vista
El viaje de una petición en ASP.NET Core MVC
Petición
El navegador pide GET /Productos
Enrutamiento
El routing elige el controlador Productos y la acción Index
Controlador
Coordina: pide los productos al modelo
Modelo
Consulta la base de datos y aplica las reglas
Vista
Razor genera el HTML de la respuesta
{controller=Home}/{action=Index}/{id?}Todo en la página vs. separar con MVC
Todo en la página
- ✕Un cambio visual puede romper la lógica
- ✕Las reglas solo se prueban abriendo el navegador
- ✕Dos personas no pueden trabajar sin chocar
- ✕El mismo SQL se repite en cada página
Con MVC
- ✓Cambias la vista sin tocar las reglas
- ✓Pruebas unitarias del modelo y del controlador
- ✓Front-end y back-end avanzan en paralelo
- ✓Cada consulta vive en un solo lugar
Ferretería del Norte: el modelo y el controlador
public class Producto { public int Id { get; set; } public string Nombre { get; set; } = ""; public decimal Precio { get; set; } public int Stock { get; set; } // Regla de negocio: vive en el modelo public bool RequiereResurtido => Stock < 5; }
public class ProductosController : Controller { private readonly FerreteriaContext _db; public ProductosController(FerreteriaContext db) => _db = db; // GET /Productos public IActionResult Index() { var productos = _db.Productos .OrderBy(p => p.Nombre).ToList(); return View(productos); } }
Paso 3: la vista muestra, no decide
@model IEnumerable<Producto> <h2>Inventario</h2> <table class="table"> @foreach (var p in Model) { <tr> <td>@p.Nombre</td> <td>@p.Precio.ToString("C")</td> <td>@p.Stock</td> <td>@(p.RequiereResurtido ? "Resurtir" : "OK")</td> </tr> } </table>
Inventario
| Producto | Precio | Stock | Estado |
|---|---|---|---|
| Cinta métrica 5 m | $95.50 | 3 | Resurtir |
| Desarmador plano | $45.00 | 20 | OK |
| Martillo 16 oz | $189.00 | 12 | OK |
| Pinzas de presión | $210.00 | 2 | Resurtir |
¿Dónde pondrías esta regla?
«No se puede registrar una venta si deja el stock de un producto en negativo.»
En la vista
Validar en el formulario antes de enviar
En el controlador
Revisar el stock en la acción Vender()
En el modelo
Un método Descontar() en la clase Producto
En un servicio
Una clase VentasService que coordina
En equipos, 5 minutos: elijan una opción y defiéndanla con una consecuencia concreta.
Tres ideas para llevarte
Cada cosa en su lugar
Datos y reglas en el Modelo, presentación en la Vista y coordinación en el Controlador.
Controladores delgados
Si un controlador tiene mucha lógica, esa lógica pertenece al modelo o a un servicio.
La base de tu proyecto
Roles, CRUD y seguridad del proyecto integrador se organizan sobre esta estructura.
Para profundizar: Freeman, A. (2023). Pro ASP.NET Core 7 (10.ª ed.). Manning Publications.
Actividad: módulo de Proveedores con MVC
Crea el modelo Proveedor (Id, Nombre, Ciudad, DiasCredito) con la regla TieneCredito.
Crea ProveedoresController con la acción Index.
Crea la vista Index.cshtml que liste los proveedores.
Entrega el proyecto, una captura y tu declaración de uso de IA (herramienta y prompts).
| Criterio (%) | Excelente | Bueno | Básico | Insuficiente |
|---|---|---|---|---|
| Modelo (25) | Propiedades y regla correctas | Regla con fallas menores | Sin regla de negocio | No compila |
| Controlador (25) | Delgado; usa el modelo | Funciona con lógica de más | Acción incompleta | No existe |
| Vista (25) | Lista completa, sin reglas | Lista con detalles menores | Datos incompletos | No se muestra |
| Separación y entrega (25) | Cada cosa en su lugar; IA declarada | Una mezcla menor | Varias mezclas | Entrega incompleta |
Niveles: Excelente 100 % · Bueno 80 % · Básico 60 % · Insuficiente 0–40 % del valor del criterio