馃摎 Contenido

C# & .NET Core: Gu铆a Definitiva Extendida

Documentaci贸n oficial de arquitectura, Clean Code y rendimiento para el desarrollo avanzado en Devlinks.

1. Introducci贸n a .NET

C# es un lenguaje manejado ("managed code") que corre en el CLR (Common Language Runtime). En las versiones modernas (.NET 6/7/8), se caracteriza por su alt铆simo rendimiento, uso extensivo de asincron铆a y compilaci贸n AOT (Ahead-of-Time).
Target Framework: En Devlinks estandarizamos el uso de .NET 8 (LTS) por sus mejoras masivas de performance en JIT (Just-In-Time) y nuevas capacidades de C# 12 (Primary constructors, Collection expressions).

2. Fundamentos y Tipado

Comprender la diferencia entre Tipos por Valor y Tipos por Referencia es cr铆tico para evitar presionar al Garbage Collector (GC).

Value Types vs Reference Types

// Value Types (Structs, ubicados en el STACK - R谩pidos) int age = 28; DateTime date = DateTime.Now; Guid id = Guid.NewGuid(); // Reference Types (Classes, ubicados en el HEAP - Recolectados por el GC) string name = "Devlinks"; List<int> numbers = new(); // Tipado Impl铆cito Moderno (Inferencia de tipo al inicializar) var user = new UserService();

3. Programaci贸n Orientada a Objetos

Records & Primary Constructors (C# 12)

// Los records son inmutables por defecto. Se eval煤an por valor. Excelente para DTOs. public record UserDto(int Id, string FirstName, string LastName); // Uso de 'with' para la mutaci贸n no destructiva var user1 = new UserDto(1, "Angel", "Tapia"); var user2 = user1 with { FirstName = "Devlinks" }; // Primary Constructors en Clases Regulares public class UserRepository(AppDbContext dbContext) { private readonly AppDbContext _db = dbContext; // ... }

Interfaces vs Abstract Classes

Usa interfaces para definir *contratos de comportamiento*, y Abstract Classes para *compartir implementaci贸n y estado central*.

public interface IEntity { int Id { get; set; } }

4. Manejo de Excepciones y Clean Code

Global Error Handler Middleware

Evita llenar tus controladores de try/catch usando un Global Exception Handler mediante middleware.

// Evitar (Anti-Patr贸n): try { ProcesarData(); } catch (Exception ex) { return StatusCode(500, ex.Message); } // Mejor: Lanzar excepciones controladas o devolver Result Patters y atrapar los errores 500 Globalmente. throw new ValidationException("Datos inv谩lidos");

5. Colecciones y LINQ Avanzado

Consultas Complejas Seguras

var activeUsers = users .Where(u => u.IsActive && u.Age >= 18) .OrderByDescending(u => u.CreatedAt) .GroupBy(u => u.Department) .Select(group => new { Department = group.Key, Count = group.Count(), LatestUser = group.First() }) .ToList();
Siempre recuerda que IEnumerable retrasa la ejecuci贸n (Lazy Evaluation). Si vas a iterar una colecci贸n de bases de datos varias veces, aseg煤rate de aplicar un .ToList() o .ToArray() para materializar los resultados.

6. Pattern Matching Avanzado

Switch con condiciones relacionales y de propiedad

decimal descuento = invoice switch { { TotalAmount: > 1000 } => 0.15m, { TotalAmount: > 500 } and { IsB2B: true } => 0.10m, _ => 0.0m }; // Type Checking if (obj is UserDto dto) { Console.WriteLine(dto.FirstName); }

7. Programaci贸n As铆ncrona (Avanzada)

Para prevenir llamadas zombis, env铆a siempre el CancellationToken a lo largo del stack de ejecuci贸n. Utiliza ValueTask si el m茅todo suele retornar valores locales sin requerir el hilo.

Task vs ValueTask y Cancellation

// Firma correcta para APIs modernas public async ValueTask<UserProfile> FetchProfileAsync(int id, CancellationToken ct) { // Pasando el CancellationToken al EF o HttpClient: return await _db.Profiles.FirstOrDefaultAsync(p => p.Id == id, ct); }

Llamadas en Paralelo con Task.WhenAll

var taskUsers = _db.Users.ToListAsync(ct); var taskRoles = _db.Roles.ToListAsync(ct); // Se procesan ambas consultas al mismo tiempo en diferentes hilos I/O await Task.WhenAll(taskUsers, taskRoles); var roles = taskRoles.Result; // Aqu铆 s铆 es l铆cito porque ya finaliz贸 WhenAll()

8. Inyecci贸n de Dependencias Superior

Patr贸n Factory y Keyed Services (.NET 8)

// Los Keyed Services evitan tener que inyectar IEnumerable<IType> para discriminar implementaciones builder.Services.AddKeyedScoped<IPaymentService, StripePaymentService>("Stripe"); builder.Services.AddKeyedScoped<IPaymentService, PaypalPaymentService>("PayPal"); // Consumo en Controller/Minimal API public class PaymentController( [FromKeyedServices("Stripe")] IPaymentService paymentService) { //... }

9. Entity Framework Core y Base de Datos

Privilegiar el Fluent API sobre los Data Annotations para mantener las entidades limpias y desacopladas de la infraestructura.

Fluent API Configuration (IEntityTypeConfiguration)

public class UserConfiguration : IEntityTypeConfiguration<User> { public void Configure(EntityTypeBuilder<User> builder) { builder.ToTable("Usuarios"); builder.HasKey(u => u.Id); builder.Property(u => u.Name) .IsRequired() .HasMaxLength(100); // Indices para optimizaci贸n builder.HasIndex(u => u.Email).IsUnique(); } }

10. Arquitectura ASP.NET Core API

Arquitectura Limpia / Capas Recomendadas

// En Devlinks escalamos separando responsabilidades: 1. Devlinks.API -> (Presentaci贸n: Controladores/Endpoints) 2. Devlinks.Application-> (L贸gica de Negocio: Casos de uso, CQRS, MediatR, DTOs) 3. Devlinks.Domain -> (Core: Entidades de Base, Value Objects, Excepciones de Dominio) 4. Devlinks.Infra -> (Datos: AppDbContext, Repositorios, Servicios Externos)