La arquitectura Model-View-Controller (MVC) es un patrón de diseño de tiempo probado que separa las preocupaciones dentro de una aplicación web, facilitando la gestión de la complejidad, los componentes de prueba en aislamiento y las características de escala con el tiempo. En ASP.NET Core, MVC es un ciudadano de primera clase, proporcionando un marco robusto para la construcción de aplicaciones web modernas y sostenibles.

Comprender el patrón MVC en la profundidad

Antes de bucear en código, es esencial comprender cómo los tres componentes básicos de MVC colaboran para manejar una solicitud de usuario. El patrón define responsabilidades claras:

  • Model: Representa la estructura de datos y las reglas de negocio. No sabe de la interfaz de usuario ni de cómo se muestran los datos. Los modelos son típicamente clases de C# simples que encapsulan propiedades, lógica de validación y acceso a datos (a menudo a través de la sección Marco de Entidades).
  • ]View: Renders the user interface. En ASP.NET Core, las vistas son los archivos Razor (`.cshtml`) que combinan el marcador HTML con el código C# del lado del servidor. Las vistas sólo deben mostrar datos, no contener lógica compleja.
  • Controller: Actúa como intermediario. Recibirá solicitudes HTTP, decide qué modelo utilizar y selecciona la opinión apropiada para regresar. Los controladores contienen métodos de acción que se mapean a rutas específicas.

El flujo de solicitud típico en ASP.NET Core MVC: un usuario navega a una acción URL (por ejemplo, ), el middleware de enrutamiento dirige la solicitud a la acción , la acción interactúa con el modelo (por ejemplo, los productos de la base de datos), empaqueta los datos en un modelo de visión, y lo pasa a la vista del cliente.

Prerrequisitos

  • .NET SDK] (versión 6.0 o posterior). Descarga de dotnet.microsoft.com.
  • Visual Studio], ]Visual Studio Code, o cualquier editor de código preferido.
  • Familiaridad básica con conceptos de C# y desarrollo web.

Paso 1: Creación de un nuevo proyecto de CVM básico ASP.NET

Puede comenzar con el .NET CLI o Visual Studio. Ambos proporcionan una plantilla de proyecto que recorre la estructura de carpeta estándar MVC.

Usando la línea de comandos

Abra una terminal y ejecute:

dotnet new mvc -n MyMvcApp

Esto crea un proyecto llamado en una nueva carpeta. La estructura generada incluye , , , y (para archivos estáticos).

Usando Visual Studio

En Visual Studio, elija Crear un nuevo proyecto → seleccione ASP.NET Core Web App (Model-View-Controller) → configure su nombre de proyecto y ubicación → elija la versión .NET (por ejemplo, .NET 8). Las mismas carpetas se crean automáticamente.

Verificar las carreras del proyecto:

cd MyMvcApp
dotnet run

Abra para ver la página de inicio predeterminada.

Paso 2: Comprender la estructura del proyecto

El proyecto andamio contiene varios elementos clave:

  • Controladores: Carpeta vacía donde se añadirán clases de controlador C#.
  • Modelos: Lugar para las clases de dominio y modelos de vista.
  • : Tiene una y ] carpeta por defecto, más una distribución.
  • Program.cs]: Inicio de aplicaciones, donde se configuran los servicios (incluyendo MVC).

Abra y observe las líneas que permiten MVC:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
var app = builder.Build();
...
app.MapControllerRoute(
 name: "default",
 pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();

Esto establece la ruta predeterminada que mapea URLs como a .

Paso 3: Creación de una clase modelo

Los modelos representan los datos con los que trabaja su aplicación. Comience creando un modelo dentro de la carpeta .

// Models/Product.cs
namespace MyMvcApp.Models;

public class Product
{
 public int Id { get; set; }
 public string Name { get; set; } = string.Empty;
 public decimal Price { get; set; }
 public string? Description { get; set; }
 public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
}

Puede enriquecer modelos con anotaciones de datos para validación:

using System.ComponentModel.DataAnnotations;

public class Product
{
 public int Id { get; set; }

 [Required(ErrorMessage = "Product name is required.")]
 [StringLength(100)]
 public string Name { get; set; } = string.Empty;

 [Range(0.01, 10000)]
 public decimal Price { get; set; }

 [MaxLength(500)]
 public string? Description { get; set; }

 [Display(Name = "Created")]
 public DateTime CreatedAt { get; set; }
}

En una aplicación real, normalmente añadiría un contexto de base de datos (Entity Framework Core) para seguir modelos. Para esta guía utilizaremos datos en memoria para mantener el enfoque en el flujo de MVC.

Paso 4: Añadiendo un controlador

Los controladores manejan las solicitudes entrantes y orquestan la respuesta. Cree una dentro de la carpeta .

// Controllers/ProductsController.cs
using Microsoft.AspNetCore.Mvc;
using MyMvcApp.Models;
using System.Collections.Generic;

namespace MyMvcApp.Controllers;

public class ProductsController : Controller
{
 // Simulate a data source
 private static List<Product> _products = new List<Product>
 {
 new Product { Id = 1, Name = "Laptop", Price = 999.99m },
 new Product { Id = 2, Name = "Smartphone", Price = 599.99m },
 new Product { Id = 3, Name = "Tablet", Price = 399.99m }
 };

 // GET: /Products
 public IActionResult Index()
 {
 return View(_products); // Pass list to the view
 }

 // GET: /Products/Details/5
 public IActionResult Details(int id)
 {
 var product = _products.Find(p => p.Id == id);
 if (product == null)
 return NotFound();
 return View(product);
 }

 // GET: /Products/Create
 public IActionResult Create()
 {
 return View();
 }

 // POST: /Products/Create
 [HttpPost]
 [ValidateAntiForgeryToken]
 public IActionResult Create(Product product)
 {
 if (ModelState.IsValid)
 {
 product.Id = _products.Max(p => p.Id) + 1;
 product.CreatedAt = DateTime.UtcNow;
 _products.Add(product);
 return RedirectToAction(nameof(Index));
 }
 return View(product);
 }
}

Puntos clave:

  • Resultado de la acción] es el tipo de retorno. Puede ser un , , , etc.
  • Mapa de nombres de acción para las vistas en una carpeta llamada después del controlador ().
  • La acción tiene dos sobrecargas: una para GET (display the form) y otra para POST (manle formulario submission).
  • protege contra la falsificación de solicitud inter-sitio.

Paso 5: Creando vistas con Razor Syntax

Las vistas viven en . El diseño compartido está en .

Vista del índice – Mostrar una lista

Crear :

@model IEnumerable<MyMvcApp.Models.Product>
@{
 ViewData["Title"] = "Product List";
}

<h2>@ViewData["Title"]</h2>

<table class="table table-striped">
 <thead>
 <tr>
 <th>@Html.DisplayNameFor(model => model.Id)</th>
 <th>@Html.DisplayNameFor(model => model.Name)</th>
 <th>@Html.DisplayNameFor(model => model.Price)</th>
 <th></th>
 </tr>
 </thead>
 <tbody>
 @foreach (var item in Model)
 {
 <tr>
 <td>@item.Id</td>
 <td>@item.Name</td>
 <td>@item.Price.ToString("C")</td>
 <td>
 <a asp-action="Details" asp-route-id="@item.Id">Details</a>
 </td>
 </tr>
 }
 </tbody>
</table>

<p>
 <a asp-action="Create" class="btn btn-primary">Create New Product</a>
</p>

Consejos de razor: Use ] para cambiar de HTML a C#, y / ayudadores de etiquetas para generar URLs.

Detalles Ver

Crear :

@model MyMvcApp.Models.Product
@{
 ViewData["Title"] = "Product Details";
}

<h2>@Model.Name</h2>

<dl class="row">
 <dt class="col-sm-2">@Html.DisplayNameFor(model => model.Id)</dt>
 <dd class="col-sm-10">@Model.Id</dd>

 <dt class="col-sm-2">@Html.DisplayNameFor(model => model.Price)</dt>
 <dd class="col-sm-10">@Model.Price.ToString("C")</dd>

 <dt class="col-sm-2">@Html.DisplayNameFor(model => model.Description)</dt>
 <dd class="col-sm-10">@Model.Description</dd>

 <dt class="col-sm-2">@Html.DisplayNameFor(model => model.CreatedAt)</dt>
 <dd class="col-sm-10">@Model.CreatedAt</dd>
</dl>

<a asp-action="Index">Back to List</a>

Crear vista con formulario

Crear :

@model MyMvcApp.Models.Product
@{
 ViewData["Title"] = "Create Product";
}

<h2>Create</h2>

<form asp-action="Create">
 <div asp-validation-summary="ModelOnly" class="text-danger"></div>

 <div class="form-group">
 <label asp-for="Name"></label>
 <input asp-for="Name" class="form-control" />
 <span asp-validation-for="Name" class="text-danger"></span>
 </div>

 <div class="form-group">
 <label asp-for="Price"></label>
 <input asp-for="Price" class="form-control" />
 <span asp-validation-for="Price" class="text-danger"></span>
 </div>

 <div class="form-group">
 <label asp-for="Description"></label>
 <textarea asp-for="Description" class="form-control"></textarea>
 </div>

 <button type="submit" class="btn btn-primary">Create</button>
 <a asp-action="Index" class="btn btn-secondary">Cancel</a>
</form>

@section Scripts {
 @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

Los ayudantes de etiquetas Razor como generan campos de formularios con unión y validación modelo. carga scripts de validación de lado cliente.

Paso 6: Añadiendo rutas de rutina y rutas personalizadas

MVC utiliza la ruta basada en convenciones por defecto. La ruta en mapas . También puede añadir la ruta de atributos para más control. Por ejemplo, en el controlador:

[Route("products")]
public class ProductsController : Controller
{
 [Route("")] // matches /products
 [Route("index")] // matches /products/index
 public IActionResult Index() { ... }

 [Route("{id:int}")] // matches /products/5
 public IActionResult Details(int id) { ... }
}

Este enfoque es útil para API RESTful cuando se combina con .

Paso 7: Utilizando ViewModels para Datos Complejos

A menudo se necesita pasar más de un objeto de datos a una vista, o incluir propiedades extra (como listas selectas, títulos de página). Ahí es donde vienen los modelos de vista. Crear una clase de modelo de visión en :

namespace MyMvcApp.Models.ViewModels;

public class ProductIndexViewModel
{
 public IEnumerable<Product> Products { get; set; }
 public string SearchString { get; set; } = string.Empty;
 public decimal MaxPrice { get; set; } = 10000;
}

Luego ajustar la acción del controlador para popular el modelo de vista y pasarlo a la vista. La vista utiliza y accede a propiedades en consecuencia.

Paso 8: Aplicación de la validación

ASP.NET Core MVC proporciona validación de lado servidor y lado cliente a través de anotaciones de datos. Añada , , , y atributos personalizados. En la vista, el muestra mensajes de error. El ] atributo de acción real

Para la lógica de validación personalizada, implemente en su modelo o cree una clase de validación separada. La documentación de validación básica ASP.NET cubre estos patrones en detalle.

Paso 9: Inyección de dependencia en los controladores

En lugar de datos de codificación dura, puede inyectar servicios (como un repositorio o un contexto de base) en el constructor del controlador. Esto promueve el acoplamiento y la testabilidad sueltas.

public class ProductsController : Controller
{
 private readonly IProductRepository _repository;

 public ProductsController(IProductRepository repository)
 {
 _repository = repository;
 }

 public IActionResult Index()
 {
 var products = _repository.GetAll();
 return View(products);
 }
}

Registrar el repositorio en :

builder.Services.AddScoped<IProductRepository, ProductRepository>();

El método ya registra los controladores para DI. Este patrón hace que su aplicación sea más limpia y más sostenible. Ver Guía de inyección de dependencia de Microsoft para más.

Paso 10: Trabajando con diseños y vistas parciales

Los diseños compartidos (por ejemplo, ]) definen la estructura general de la página. Para personalizar, modificar el en . Puede definir secciones, o utilizar vistas parciales para componentes de interfaz de usuario reutilizables como navegación, calzado o renderizado de tarjetas de producto.

Ejemplo de vista parcial :

@model Product
<div class="card">
 <div class="card-body">
 <h5 class="card-title">@Model.Name</h5>
 <p class="card-text">Price: @Model.Price.ToString("C")</p>
 <a asp-action="Details" asp-route-id="@Model.Id" class="btn btn-primary">Details</a>
 </div>
</div>

Incluya en cualquier punto de vista con .

Paso 11: Códigos de manejo y estado de errores

Los controladores deben manejar con gracia errores. Use bloques o un controlador de excepción global a través de middleware. Devuélvase códigos de estado HTTP apropiados:

  • para 404
  • por 400
  • para errores del servidor.

También puede añadir una vista de error personalizada: ya está incluido en la plantilla. Set en para redirigir a excepciones en la producción.

Paso 12: Prueba la aplicación MVC

El análisis es crítico. Use xUnit y el paquete para escribir pruebas de integración. Ejemplo para la acción :

public class ProductsControllerTests : IClassFixture<WebApplicationFactory<Program>>
{
 private readonly HttpClient _client;

 public ProductsControllerTests(WebApplicationFactory<Program> factory)
 {
 _client = factory.CreateClient();
 }

 [Fact]
 public async Task Index_ReturnsSuccessAndCorrectContentType()
 {
 var response = await _client.GetAsync("/products");
 response.EnsureSuccessStatusCode();
 Assert.Equal("text/html; charset=utf-8",
 response.Content.Headers.ContentType.ToString());
 }
}

La unidad prueba el controlador con servicios cortados para la lógica de aislamiento. La documentación de prueba ASP.NET Core proporciona ejemplos extensos.

Mejores prácticas y consejos avanzados

  • Mantenga los controladores delgados: La lógica empresarial pertenece a los servicios/repositorios, no en los métodos de acción.
  • Utilice modelos de vista: Evite pasar modelos de dominio directamente a las vistas; utilice modelos de vista dedicados para configurar los datos según sea necesario.
  • Ayudadores de etiquetas de aprendizaje: Hacen limpiador de HTML y reducen errores en la unión de formularios.
  • Permitir la validación del lado del cliente : Incluir y paquetes (ya en ).
  • Usar acciones asinc para operaciones con I/O: con .
  • Ejecuta tu aplicación: Usa siempre HTTPS, fichas anti-forgery en formas POST, y autorización basada en el papel a través de .

Conclusión

Implementar la arquitectura MVC en ASP.NET Core te da una base sólida para construir aplicaciones web que se organizan, testifican y mantienen. Al separar modelos, vistas y controladores, puedes trabajar en cada componente de forma independiente y escalar tu aplicación con confianza. Los pasos en esta guía proporcionan un completo paso de la creación de proyectos a patrones de producción. Empieza con un proyecto simple, luego agrega la integración de bases de datos, la autenticación y las características avanzadas [LT]