ASP.NET Core: Ejemplos Prácticos 🚀

Ejemplos de código funcionales y listos para usar, desde la configuración hasta la persistencia de datos.

⚙️ Ejemplo 1: Configuración Mínima y Middleware

Este es el punto de partida de toda aplicación ASP.NET Core (usando el modelo minimalista de .NET 6+).

Archivo: Program.cs


// 1. Crear el Constructor del WebApplication
var builder = WebApplication.CreateBuilder(args);

// 2. Definir servicios (Contenedor de Inyección de Dependencias)
builder.Services.AddControllers(); // Habilita controladores API/MVC
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

// 3. Construir la aplicación
var app = builder.Build();

// 4. Configurar el pipeline HTTP (Middleware)
if (app.Environment.IsDevelopment())
{
    // Middleware que solo se ejecuta en modo Desarrollo
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseAuthorization();

// 5. Mapear endpoints (API, MVC, etc.)
app.MapControllers(); // Rutas automáticas para los controladores

// Endpoint simple de ejemplo (Middleware personalizado)
app.MapGet("/", () => "¡Hola, ASP.NET Core con Gemini!");

// 6. Ejecutar la aplicación
app.Run();
            

Explicación: El **`builder`** configura los servicios (DI), y el objeto **`app`** configura el *pipeline* de middleware y las rutas (`Map*`).


🗺️ Ejemplo 2: Creación de un Controlador RESTful

Un ejemplo de un controlador simple que gestiona una colección de elementos (simulando una lista de tareas).

Archivo: Controllers/TareasController.cs


using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Linq;

[ApiController]
[Route("api/[controller]")]
public class TareasController : ControllerBase
{
    // Simulación de la base de datos
    private static List<string> _tareas = new List<string> { "Comprar leche", "Aprender ASP.NET Core" };

    [HttpGet] // GET: api/tareas
    public ActionResult<IEnumerable<string>> Get()
    {
        return Ok(_tareas);
    }

    [HttpPost] // POST: api/tareas
    public IActionResult Post([FromBody] string nuevaTarea)
    {
        if (string.IsNullOrEmpty(nuevaTarea))
        {
            return BadRequest("La tarea no puede estar vacía.");
        }
        _tareas.Add(nuevaTarea);
        return CreatedAtAction(nameof(Get), nuevaTarea); 
    }
    
    [HttpDelete("{id}")] // DELETE: api/tareas/1
    public IActionResult Delete(int id)
    {
        if (id < 0 || id >= _tareas.Count)
        {
            return NotFound();
        }
        _tareas.RemoveAt(id);
        return NoContent(); // 204 No Content (Éxito sin devolver cuerpo)
    }
}
            

Explicación: Usamos los atributos **`[HttpGet]`**, **`[HttpPost]`**, etc., para mapear los métodos del controlador a los verbos HTTP. **`ControllerBase`** proporciona métodos de resultado HTTP (`Ok`, `NotFound`, `NoContent`).


💾 Ejemplo 3: Configuración de Entity Framework Core

Pasos necesarios para configurar un contexto de base de datos (usando SQLite in-memory para simplificar).

Archivo: Program.cs (Adición de servicio)


// ... dentro de la sección de servicios (builder.Services) ...

builder.Services.AddDbContext<AppDbContext>(options =>
    options.UseSqlite("Data Source=MiBaseDeDatos.db"));

// Nota: Necesitas instalar el paquete Microsoft.EntityFrameworkCore.Sqlite
            

Archivo: Data/AppDbContext.cs (Contexto y Modelo)


using Microsoft.EntityFrameworkCore;
using SuProyecto.Models; // Asumiendo que Tarea.cs está aquí

public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options)
        : base(options)
    {
    }

    // Un DbSet por cada tabla/entidad que quieras mapear
    public DbSet<Tarea> Tareas { get; set; }
}

// Ejemplo de Modelo (Data/Tarea.cs)
public class Tarea
{
    public int Id { get; set; }
    public string Descripcion { get; set; }
    public bool EstaCompleta { get; set; }
}
            

Explicación: **`AddDbContext`** registra el contexto en el contenedor DI. **`AppDbContext`** hereda de `DbContext` y usa `DbSet` para definir las colecciones que mapean a las tablas.


💉 Ejemplo 4: Inyección de Dependencias en un Controlador

Cómo consumir el contexto de base de datos o cualquier otro servicio registrado directamente en el constructor del controlador.

Archivo: Controllers/TareasController.cs (Inyección)


[ApiController]
[Route("api/[controller]")]
public class TareasController : ControllerBase
{
    private readonly AppDbContext _context;

    // EL CONSTRUCTOR SOLICITA LA DEPENDENCIA
    public TareasController(AppDbContext context)
    {
        _context = context;
    }

    [HttpGet("{id}")]
    public async Task<ActionResult<Tarea>> GetTarea(int id)
    {
        // USO DE LA DEPENDENCIA INYECTADA
        var tarea = await _context.Tareas.FindAsync(id);

        if (tarea == null)
        {
            return NotFound();
        }

        return tarea;
    }

    // ... otros métodos CRUD (Create, Update, Delete)
}
            

Explicación: El contenedor de Inyección de Dependencias (DI) de ASP.NET Core automáticamente resuelve y proporciona una instancia de **`AppDbContext`** al controlador cuando se necesita, siempre y cuando se haya registrado previamente en `Program.cs`.


🔐 Ejemplo 5: Seguridad (JWT) y Manejo de Errores Global

Ejemplos de cómo asegurar tu API y cómo manejar excepciones de forma centralizada.

Manejo de Errores Global (Middleware)

Usaremos un middleware personalizado para capturar todas las excepciones y devolver un formato JSON estándar (500 Internal Server Error).


// En Program.cs, justo después de app.UseHttpsRedirection();

if (app.Environment.IsDevelopment())
{
    // En desarrollo, usamos el manejo de errores detallado de ASP.NET
    app.UseDeveloperExceptionPage();
}
else
{
    // En producción, usamos un manejador simple y consistente
    app.UseExceptionHandler("/error"); 
}

// Endpoint que captura errores y devuelve un JSON
app.Map("/error", (HttpContext context) =>
{
    var exceptionHandlerPathFeature = context.Features.Get<IExceptionHandlerPathFeature>();
    
    // Devolver un objeto de error simple
    return Results.Problem(
        detail: exceptionHandlerPathFeature?.Error.Message,
        title: "Ocurrió un error inesperado en el servidor",
        statusCode: 500
    );
});
            

Explicación: **`UseExceptionHandler`** redirige todas las excepciones no controladas a un *endpoint* simple (`/error`), donde se extrae la información y se devuelve un objeto **`ProblemDetails`** (estándar para errores de API).

Configuración de Autenticación JWT (JSON Web Token)

Pasos para configurar la autenticación basada en tokens, necesaria para proteger tus endpoints.


// 1. Instalar paquetes: Microsoft.AspNetCore.Authentication.JwtBearer
// 2. En Program.cs, dentro de builder.Services.Add...
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = builder.Configuration["Jwt:Issuer"],
            ValidAudience = builder.Configuration["Jwt:Audience"],
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]))
        };
    });

// 3. Habilitar el middleware de autenticación (ANTES de app.MapControllers)
app.UseAuthentication();
app.UseAuthorization();
            

Protegiendo un Endpoint


using Microsoft.AspNetCore.Authorization;
// ... (otros using)

[ApiController]
[Route("api/[controller]")]
public class ArticulosController : ControllerBase
{
    [Authorize] // Este atributo requiere un token válido en el encabezado
    [HttpGet] 
    public IActionResult GetArticulosProtegidos()
    {
        // Solo usuarios con un token JWT válido llegarán aquí.
        return Ok(new { mensaje = "Datos sensibles del usuario autenticado." });
    }
}
            

Explicación: **`AddAuthentication`** configura el esquema de JWT. El middleware **`UseAuthentication`** lee el token. El atributo **`[Authorize]`** en el controlador fuerza la validación de ese token.