Enviar e-mails en ASP.NET MVC

Introducción: ¿Por qué complicarse con los e-mails en ASP.NET MVC?

Enviar e-mails desde una aplicación web puede sonar tan divertido como leer la documentación del SAT, pero hey, es necesario.

Ya sea para confirmar registros, enviar recordatorios o simplemente para decir «Hola, gracias por registrarte«, necesitas un sistema de e-mails robusto.

Y ahí entra MvcMailer como un superhéroe que no sabías que necesitabas.

¿Qué es MvcMailer y por qué deberías usarlo?

MvcMailer es una librería que facilita la vida al trabajar con e-mails en ASP.NET MVC.

Combina lo mejor de Razor (las vistas que ya amas) con el poder del correo electrónico. En lugar de estar armando cadenas de HTML como si fuera 1999, puedes usar vistas y layouts tal como en tus páginas normales. 🤯

Instalación paso a paso (sin perder la paciencia)

Abra su consola de NuGet y escriba la fórmula mágica:

Install-Package Mvc.Mailer

Eso es todo. Bueno, casi. Asegúrate de tener referencias a System.Net.Mail y Mvc.Mailer en tu proyecto. Nada que un Ctrl + . no pueda arreglar.

Configuración del SMTP (sí, esa parte aburrida pero necesaria)

En tu Web.config, añade lo siguiente dentro de <system.net>:

<system.net>
  <mailSettings>
    <smtp from="tucorreo@dominio.com">
      <network host="smtp.gmail.com" port="587" userName="tucorreo@dominio.com" password="tu_contraseña" enableSsl="true" />
    </smtp>
  </mailSettings>
</system.net>

Pro tip: Usa variables de entorno para no dejar tus contraseñas paseando por el código.

Creando tu primera clase Mailer: que empiece la magia

Crea una clase que herede de MailerBase:

public class UsuarioMailer : MailerBase
{
    public EmailResult Bienvenida(string nombre, string email)
    {
        ViewBag.Nombre = nombre;
        return Email("Bienvenida", email);
    }
}

Listo, ya tienes una clase que puede disparar un e-mail con nombre personalizado. ¡Casi como magia negra, pero legal!

Diseñando la vista del e-mail (porque sí, el diseño también cuenta)

Crea una vista Razor en Views/UsuarioMailer/Bienvenida.cshtml:

<h2>¡Hola @ViewBag.Nombre!</h2>
<p>Gracias por registrarte en nuestro sitio. Estamos felices de tenerte a bordo. 🎉</p>

Simple, directo y sin Comic Sans.

Llamando al mailer desde tu controller sin romper nada

En tu controller:

public ActionResult EnviarBienvenida(string nombre, string email)
{
    var mailer = new UsuarioMailer();
    mailer.Bienvenida(nombre, email).Send();
    return Content("Correo enviado a " + email);
}

Boom. El usuario recibe un correo sin que se caiga el servidor (con suerte).

try
{
mailer.Bienvenida(nombre, email).Send();
}
catch (Exception ex)
{
// Loguea el error, muestra un mensaje amigable o llama a los bomberos.
Console.WriteLine(ex.Message);
}

Consejos finales para que tus correos no terminen en spam

👉 Usa asuntos claros y sin palabras tipo «GRATIS DINERO RÁPIDO» 👉 Evita usar solo imágenes en el contenido 👉 Configura SPF y DKIM en tu dominio 👉 Pide al usuario que te agregue a su lista de contactos (sin llorar)

Conclusión: enviar e-mails nunca fue tan humano (ni tan divertido)

Y ya está.

Ahora puedes enviar correos desde tu app ASP.NET MVC como si fueras Tony Stark automatizando su cafetera. MvcMailer te ahorra tiempo, código repetitivo y muchas frustraciones.

¿El siguiente paso? Adjuntos, templates con CSS, y por qué no, notificaciones push. Pero eso… eso es historia para otro post 😉

Plantillas de texto para C#

Introducción

¿Alguna vez te encontraste escribiendo bloques eternos de String.Format, StringBuilder o peor… ¿concatenación a lo cavernícola? 😩

Pues déjame decirte: hay una mejor manera de hacer esto.

Su nombre es Nustache, y aunque suena como un bigote hipster, es en realidad una herramienta bien práctica para trabajar con plantillas de texto en C#.

Vamos a entrarle.

¿Qué demonios es Nustache y por qué debería importarte?

Nustache es una implementación de Mustache para C#.

Mustache, por si no lo sabías, es un motor de plantillas minimalista y sin lógica (sí, como algunos jefes 😅),

Con Nustache puedes generar texto (HTML, JSON, correos, etc.) a partir de plantillas con llaves dobles: {{nombre}}. Así de fácil.

💡 Piensa en Nustache como el String.Format con esteroides, pero sin que tengas que llorar por el orden de los parámetros.

Ventajas de usar Nustache en tus proyectos C#

✅ Separas lógica de presentación.
✅ Plantillas legibles, como Dios manda.
✅ Compatible con cualquier tipo de texto (¡no solo HTML!).
✅ Ideal para microservicios, correos automáticos, reportes y más.
✅ No dependes de ASP.NET ni cosas pesadas como Razor.

Instalación sin dramas: Cómo añadir Nustache a tu proyecto

Abre tu consola de NuGet y ejecuta:

Install-Package Nustache.Core

O si estás en el mundo moderno con .NET CLI:

dotnet add package Nustache.Core

🎉 ¡Listo! Ya puedes dejar de escribir cadenas con 12 + seguidos.

Hola mundo con Nustache: Tu primera plantilla

using Nustache.Core;

var plantilla = "Hola {{nombre}}, bienvenido a la jungla.";
var datos = new { nombre = "Neo" };

var resultado = Render.StringToString(plantilla, datos);
Console.WriteLine(resultado);

Salida:

Hola Neo, bienvenido a la jungla.

Más fácil que hacer un café en la oficina (siempre que no se haya roto la máquina otra vez).

Variables, loops y condicionales: La magia de las plantillas

🔄 Loop:

var plantilla = "Tus frutas favoritas: {{#frutas}}{{.}}, {{/frutas}}";
var datos = new { frutas = new[] { "manzana", "banana", "kiwi" } };

Salida:

Tus frutas favoritas: manzana, banana, kiwi,

⚖️ Condicional:

var plantilla = "{{#esAdmin}}Tienes acceso total.{{/esAdmin}}{{^esAdmin}}Acceso limitado.{{/esAdmin}}";
var datos = new { esAdmin = true };

Salida:

Tienes acceso total.

Separando lógica y presentación como un pro

En lugar de tener todo embutido en tu código, puedes tener un archivo .mustache y cargarlo desde allí. Ejemplo:

plantilla.mustache

Hola {{nombre}}, tu pedido #{{pedido}} ha sido enviado 🚚.
var resultado = Render.FileToString("plantilla.mustache", new { nombre = "Luisa", pedido = 123 });

Así tu código no parece una receta de cocina mal escrita.

Ejemplos prácticos para la vida real (o casi)

Correos automáticos:
«Hola {{cliente}}, tu suscripción vence el {{fecha}}. No te olvides 😉»

Facturas:
«Subtotal: {{subtotal}}, IVA: {{iva}}, Total: {{total}}»

Contratos (sí, legales también):
«El empleado {{nombre}} acuerda trabajar hasta que la laptop explote 💥»

Errores comunes y cómo evitarlos sin llorar (mucho)

❌ Usar propiedades que no existen en tu modelo → Nada se muestra, y tú te preguntas si ya rompiste todo.

✅ Usa nombres exactos en tu plantilla y en tu objeto de datos.

❌ Loops mal cerrados → El clásico: abre con {{#cosas}} y olvida el {{/cosas}}.

✅ ¡Cierra siempre tus bloques! Como los ciclos for, pero con bigotes.

¿Y ahora qué? Integrando Nustache en aplicaciones más grandes

Puedes usarlo para:

  • 📧 Enviar emails desde un backend con plantillas dinámicas.
  • 📝 Generar documentos automáticos.
  • 🖥️ Crear contenido dinámico en apps de escritorio.
  • 📦 Serializar contenido para APIs o microservicios.

¿Lo mejor? No necesitas aprender nada más. Es tan simple que hasta podrías usarlo para escribir cartas de amor automáticas ❤️ (aunque no lo recomiendo).

Conclusión: ¿Vale la pena o es otra moda pasajera?

Si odias String.Format, si Razor te parece un cañón para matar moscas y si quieres algo rápido, liviano y simple, entonces sí, Nustache es tu nuevo BFF.

¿Tiene limitaciones? Claro. No te va a preparar café ni te va a conseguir pareja. Pero para tareas de generación de texto, es una joya.

¿Y tú? ¿Ya habías probado Nustache? ¿O sigues peleándote con los + como en 2003?
Déjame tus comentarios, dudas, quejas o memes 👇 ¡Nos leemos!

Ejecución de tareas con HangFire

¿Qué rayos es Hangfire y por qué debería importarte?

Hangfire es una librería para .NET que te permite ejecutar tareas en segundo plano de forma fácil, confiable y sin dolor de cabeza.

Es como tener un mayordomo que se encarga de hacer las tareas sucias mientras tu aplicación sigue atendiendo a los usuarios.

Con Hangfire puedes:

  • Lanzar tareas una sola vez, de inmediato o con retraso.
  • Programar tareas recurrentes tipo cron.
  • Encadenar tareas (sí, puedes hacer workflows 😎).
  • Ver todo en un dashboard web.

Y lo mejor: sin necesidad de Windows Services, ni procesos externos, ni hacks con Task.Run(). Solo .NET, un poco de magia y listo.

¿Por qué no simplemente usar un Thread.Sleep()?

Ah, la vieja confiable. Claro, podrías usar Thread.Sleep(), Timer, o incluso un while(true) con await Task.Delay()… si lo que quieres es construir una bomba de tiempo en tu app 💣.

¿El problema?

  • Bloqueas el hilo y tu app se vuelve una tortuga. 🐢
  • No hay control, no hay logs, no hay dashboard.
  • No es escalable ni confiable.
  • Si el servidor se cae, chao tarea.

¿Ves por qué Hangfire es el camino? 😉

Instalación de Hangfire en 3 minutos (o menos, si tienes café ☕)

  1. Abre tu terminal o consola del package manager.
  2. Instala el paquete mágico:
dotnet add package Hangfire
dotnet add package Hangfire.AspNetCore
  1. (Opcional pero recomendado) Si vas a guardar tareas en base de datos, instala el provider para SQL Server:
dotnet add package Hangfire.SqlServer

Sí, así de fácil. No hay excusa.

Configurando el motor: Startup.cs y lo que no debes olvidar

En tu clase Startup.cs o donde configures los servicios:

public void ConfigureServices(IServiceCollection services)
{
    services.AddHangfire(config =>
        config.UseSqlServerStorage("TuConnectionString")); // Usa tu propia connection string

    services.AddHangfireServer();
}

Y en el método Configure:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseHangfireDashboard(); // Habilita el dashboard

    // Opcional: restringir acceso
    app.UseHangfireDashboard("/hangfire", new DashboardOptions
    {
        Authorization = new[] { new MyAuthorizationFilter() }
    });
}

Listo, Hangfire está vivo. ⚡

Tipos de tareas que puedes ejecutar (y cómo no romper nada)

🔥 Fire-and-forget

BackgroundJob.Enqueue(() => Console.WriteLine("Hola desde Hangfire!"));

Ejecuta una vez, de inmediato. Ideal para tareas como enviar un email, procesar datos, etc.

⏰ Recurring jobs

RecurringJob.AddOrUpdate(
    "job-diario",
    () => Console.WriteLine("Ejecutado todos los días"),
    Cron.Daily);

Sí, puedes usar expresiones tipo CRON. Y sí, puedes hacer que algo se ejecute cada minuto si eres masoquista.

⌛ Delayed jobs

BackgroundJob.Schedule(
    () => Console.WriteLine("Tarea con retraso"),
    TimeSpan.FromMinutes(5));

Se ejecuta una vez, pero en el futuro. Como los buenos memes.

🔗 Continuations

var jobId = BackgroundJob.Enqueue(() => Metodo1());
BackgroundJob.ContinueJobWith(jobId, () => Metodo2());

Porque a veces necesitas que una tarea termine para que empiece otra.

Dashboard de Hangfire: el lugar donde todo se ve bonito (hasta que falla 😅)

Accede a http://localhost:5000/hangfire (o el puerto que uses). Desde ahí puedes:

✅ Ver qué tareas se ejecutaron
🕒 Ver tareas programadas
🛠️ Reintentar errores
🗑️ Borrar jobs fallidos

Es como el «Task Manager» de tus tareas en segundo plano. Y sí, es adictivo.

Ejemplos prácticos que sí funcionan (probados por humanos, no por IA)

Enviar un email

BackgroundJob.Enqueue(() => emailService.Send("hola@tucorreo.com", "¡Hola!", "Mensaje de prueba"));

Procesar una imagen

BackgroundJob.Enqueue(() => imageProcessor.Resize("imagen.jpg"));

Generar reportes diarios

RecurringJob.AddOrUpdate(() => reporteService.Generar(), Cron.Daily);

Errores comunes que todos hemos cometido (y cómo arreglar el desastre)

  • ❌ No registraste el servidor de Hangfire (AddHangfireServer())
  • ❌ Estás usando una base de datos inestable (bye SQLite…)
  • ❌ Estás inyectando servicios con scoped en un job estático
  • ❌ Te olvidaste de manejar excepciones en tus métodos

Y sí, todo esto lo aprendí a la mala 😅

Consejillos para producción: Hangfire no es magia, es ingeniería

  • Usa un almacenamiento persistente (SQL Server, Redis, etc)
  • Protege el dashboard, no dejes /hangfire público 🙈
  • Usa logs y retries para tareas críticas
  • Configura time-outs y excepciones personalizadas

Conclusión: ¿Vale la pena usar Hangfire o sigo con mi script de consola?

Mira… si estás haciendo algo más complejo que un «Hola Mundo«, sí, vale la pena. Hangfire te da:

✅ Simplicidad
✅ Fiabilidad
✅ Dashboard bonito
✅ Escalabilidad

Y todo con una curva de aprendizaje suavecito. Así que ya sabes: ¡pon a Hangfire a trabajar mientras tú tomas un café! ☕

Ventajas y desventajas de un ORM

Introducción

¿ORM? ¿Eso no era una marca de shampoo? Nah, nada que ver.

Si estás metido en el mundo del desarrollo, especialmente en backend, tarde o temprano te topas con esos benditos ORMs.

Algunos los aman como si fueran el iPhone del código. Otros… bueno, preferirían escribir mil líneas de SQL con sangre.

Pero, ¿vale la pena usarlos? Vamos a destriparlos juntos

¿Qué diablos es un ORM?

Como ya vimos en otra entrada, un ORM (Object-Relational Mapping) es esa capa mágica que se interpone entre tu aplicación y tu base de datos. En lugar de escribir consultas SQL, trabajas con objetos. Es como pedirle a un mesero que le hable al chef por ti… solo que a veces el mesero se pone creativo y no pide lo que tú querías 🫠

Ejemplos conocidos:

Ventajas de usar un ORM

🚀 Desarrollo más rápido

No tienes que andar escribiendo cada SELECT, INSERT y DELETE. El ORM lo hace por ti, y tú te puedes enfocar en lo que importa: ir por otro café ☕.

🤯 Código más limpio y mantenible

Tu código parece poesía. No hay mezcla rara de SQL metido en strings por ahí. Todo se ve más ordenado y hasta da gusto abrir el proyecto (a veces).

🔄 Independencia de base de datos

Hoy estás con MySQL, mañana con PostgreSQL… y el ORM ni se inmuta. Tú cambias de pareja y él lo acepta como si nada ❤️

🛡️ Seguridad integrada

Adiós a las inyecciones SQL (o al menos, muchas de ellas). El ORM escapa los valores por ti. O sea, te cuida más que tu ex.

🧩 Integración fácil con frameworks

Django, Laravel, Spring… todos tienen su ORM listo para usar. Es como comprar un mueble de IKEA con instrucciones claras (por una vez).

Desventajas de usar un ORM

🐢 Rendimiento… no siempre es su fuerte

Cuando el ORM empieza a hacer consultas raras que ni tú entiendes, y la app se arrastra como tortuga con jet lag 🐢.

🧠 Curva de aprendizaje

“¿Cómo demonios relaciono dos modelos?”, “¿por qué me lanza este error raro?”. Prepárate para leer documentación como si fuera la biblia del código.

🧙‍♂️ Abstracción excesiva

A veces no sabes qué rayos está haciendo debajo. El ORM te promete magia… pero como todo mago, no muestra sus trucos.

🧪 Consultas complejas = caos

JOINs locos, subconsultas, filtros avanzados… el ORM se empieza a desmayar y tú terminas escribiendo SQL igual. Irónico, ¿no?

🕵️ Difícil de depurar

Cuando algo falla, el error no está en tu código… está en la sombra del ORM, y encontrarlo es como buscar a Wally en Mordor.

ORM vs SQL puro: ¿cuál es el elegido?

El ORM gana cuando:

  • El proyecto es mediano y no necesitas performance extremo
  • Quieres moverte rápido y no complicarte con SQL
  • Hay muchos devs nuevos en el equipo

El SQL manda cuando:

  • Necesitas consultas ultra-optimizada
  • La base de datos es gigante
  • El rendimiento es sagrado (tipo fintech o gaming online)

¿Cuándo deberías usar un ORM y cuándo NO?

✅ Usa un ORM si:

  • Tu proyecto es tipo CRUD básico o mediano
  • Prefieres enfocarte en la lógica y no en las consultas
  • Estás usando un framework que lo trae por defecto

❌ Evita un ORM si:

  • Necesitas un control quirúrgico de la base de datos
  • Tienes consultas MUY específicas
  • Quieres mantener tu stack lo más liviano posible

Conclusión con veneno

El ORM no es ni un santo ni el diablo. Es una herramienta. Úsala bien, y serás feliz. Úsala mal… y prepárate para llorar en silencio en la ducha.

Y tú, ¿amas u odias los ORMs?

Cuéntame en los comentarios si eres del #TeamORM o del lado oscuro del SQL puro. Prometo no juzgarte… mucho 😏

¿Qué es NHibernate?

Introducción

Hola,

Antes de empezar, déjame decirte que si no sabes lo que es un ORM, deberías leerte esta entrada.

Recordemos que un ORM es una librería/framework que nos permite convertir datos entre un sistema orientado a objetos y una base de datos relacional.

Si trabajas con C# y te has peleado alguna vez con SQL, probablemente ya te preguntaste si hay una forma más simple de conectar tu código con la base de datos.

Spoiler: ¡sí la hay! Y se llama NHibernate.

Pues hoy he venido a hablarte de NHibernate, un ORM para C#.

Vamos a verlo …

¿Qué es NHibernate?

NHibernate es un ORM (Object-Relational Mapper) para C#.

NHibernate es un port para C# del proyecto Hibernate en Java.

¿Eso qué significa? Básicamente, que te permite trabajar con tu base de datos como si estuvieras usando objetos normales de C#. En lugar de escribir consultas SQL por todos lados, usas clases, propiedades y métodos. Así de fácil.

¿Y lo mejor? NHibernate se encarga de traducir tus objetos en tablas, columnas y registros… sin que tengas que tocar ni una línea de SQL (a menos que quieras). Es como tener un asistente personal que se encarga del papeleo mientras tú te concentras en la lógica de tu aplicación.

¿Suena bien, no? Pues eso es solo el comienzo.

En este entrada vamos a ver qué hace a NHibernate tan útil.

Ahora que ya sabes qué es NHibernate, es momento de arremangarse y ver cómo se usa en la vida real.

Vamos a construir algo simple, paso a paso, para que veas el flujo completo.

¿Listo?

Clase

Primero, imaginemos que queremos construir una app para guardar libros. Sí, un clásico 🙂

Creamos una clase sencilla:

public class Libro
{
    public virtual int Id { get; set; }
    public virtual string Titulo { get; set; }
    public virtual string Autor { get; set; }
    public virtual int Anio { get; set; }
}

La palabra virtual es importante. NHibernate la usa para hacer su magia con los proxies.

Archivo de mapping

Sí, NHibernate usa archivos .hbm.xml. Pero no te asustes, es más fácil de lo que suena.

Creamos un archivo para la clase Libro que hemos creado llamado Libro.hbm.xml:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class name="TuProyecto.Modelo.Libro" table="Libros">
    <id name="Id">
      <generator class="identity"/>
    </id>
    <property name="Titulo"/>
    <property name="Autor"/>
    <property name="Anio"/>
  </class>
</hibernate-mapping>

Ojo con la ruta en name. Tiene que coincidir con el namespace completo de tu clase.

Configuración

Ahora toca decirle a NHibernate cómo conectarse a la base de datos.

Crea un archivo hibernate.cfg.xml en la raíz del proyecto:

<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
  <session-factory>
    <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
    <property name="connection.connection_string">
      Data Source=localhost;Initial Catalog=MiLibreria;Integrated Security=True
    </property>
    <property name="dialect">NHibernate.Dialect.MsSql2012Dialect</property>
    <property name="show_sql">true</property>
    <mapping resource="TuProyecto.Modelo.Libro.hbm.xml"/>
  </session-factory>
</hibernate-configuration>

Si usas otro motor (como PostgreSQL), cambia el driver_class y el dialect.

Uso

Ahora sí, lo bueno: usar NHibernate en el código:

using NHibernate;
using NHibernate.Cfg;

class Program
{
    static void Main()
    {
        var cfg = new Configuration();
        cfg.Configure(); // Lee hibernate.cfg.xml
        var sessionFactory = cfg.BuildSessionFactory();

        using (var session = sessionFactory.OpenSession())
        using (var transaction = session.BeginTransaction())
        {
            var libro = new Libro
            {
                Titulo = "C# para humanos",
                Autor = "Jane Doe",
                Anio = 2024
            };

            session.Save(libro);  // ¡Guardado con magia!
            transaction.Commit();
        }
    }
}

Conclusiones

Como hemos visto, utilizar NHibernate no es tan complicado como suena.

Al principio puede parecer que hay muchas piezas (clases, XML, configuración…), pero una vez que lo armas, todo fluye como si fuera magia. Es como montar una bicicleta: cuesta un poco al principio, pero luego te lleva a donde quieras sin esfuerzo.

NHibernate te da flexibilidad, control total y una forma elegante de manejar tus datos sin ensuciar tu código con SQL por todos lados. Ideal si te gusta tener el poder en tus manos y no depender de frameworks que te imponen su forma de trabajar.

¿Vale la pena aprenderlo? Totalmente. Especialmente si trabajas con proyectos grandes, legacy o necesitas algo más personalizable que Entity Framework.

¿El siguiente paso? Jugar con consultas, relaciones entre tablas, y si no te gusta el XML, pásate a Fluent NHibernate.

Lo importante es que ahora ya sabes cómo dar el primer paso… y eso, amigo/a, es lo más difícil de cualquier camino.

¿Qué es Entity Framework Core?

Introducción

Hola,

Antes de empezar, déjame decirte que si no sabes lo que es un ORM, deberías leerte esta entrada.

Recordemos que un ORM es una librería/framework que nos permite convertir datos entre un sistema orientado a objetos y una base de datos relacional.

Si trabajas con C# y te has peleado alguna vez con SQL, probablemente ya te preguntaste si hay una forma más simple de conectar tu código con la base de datos.

Spoiler: ¡sí la hay! Y se llama Entity Framework Core.

Pues hoy he venido a hablarte de Entity Framework Core, un ORM para C#.

Vamos a verlo …

¿Qué es Entity Framework Core?

Entity Framework Core es un ORM (Object-Relational Mapper) para C# creado por Microsoft.

Básicamente, te permite trabajar con bases de datos (como SQL Server, PostgreSQL, MySQL, etc.) usando código C# en lugar de escribir SQL directamente.

¿Eso qué significa? Básicamente, que te permite trabajar con tu base de datos como si estuvieras usando objetos normales de C#.

En lugar de escribir consultas SQL por todos lados, usas clases, propiedades y métodos. Así de fácil.

¿Y lo mejor? Entity Framework Core se encarga de traducir tus objetos en tablas, columnas y registros… sin que tengas que tocar ni una línea de SQL (a menos que quieras).

Es como tener un asistente personal que se encarga del papeleo mientras tú te concentras en la lógica de tu aplicación.

¿Suena bien, no? Pues eso es solo el comienzo.

En este entrada vamos a ver qué hace a Entity Framework Core tan útil.

Pero antes deja contarte un poco de su historia …

Historia de la evolución de Entity Framework

Todo empezó en el 2007 …

LINQ to SQL

Antes de que existiera Entity Framework, Microsoft lanzó en el 2007, LINQ to SQL con .NET Framework 3.5.

Fue la primera gran apuesta de Redmond para permitir que los desarrolladores interactuaran con bases de datos usando LINQ (Language Integrated Query). ¿La idea? Escribir consultas SQL… pero desde C#. ¡Una locura para la época!

Era sencillo, rápido y muy integrado a Visual Studio. Pero tenía un problema: sólo funcionaba con SQL Server. Además, su diseño estaba limitado y no soportaba escenarios complejos.

Entonces Microsoft dijo: “vamos a hacerlo bien desde cero”.

Microsoft dejó claro desde hace años que LINQ to SQL no seguiría evolucionando. Aunque sigue funcionando, no es recomendable para nuevos proyectos. EF (y especialmente EF Core) lo superó por completo en flexibilidad, soporte y comunidad.

Entity Framework

En el 2008 llegó Entity Framework 1.0 con ADO.NET. La promesa era grande: un ORM completo que sirviera como puente entre el mundo de los objetos en C# y las tablas de una base de datos relacional.

Pero… no fue amor a primera vista.

La primera versión era muy limitada, y la comunidad no la recibió con los brazos abiertos. Muchos incluso preferían seguir usando LINQ to SQL por su simplicidad.

EF 4.x y 5.0

El 2010 Microsoft publico EF 4.0 (no hubo versión 2 ni 3 para empatar con .NET Framework) trajo varias mejoras y, lo más importante, llegó Code First en la 4.1.

Ahora sí: podías escribir tus clases y dejar que EF generara la base de datos. Adiós a diseñadores visuales, hola a la libertad del código.

EF 5.0 consolidó muchas mejoras: soporte para enums, spatial data types, y más rendimiento.

EF 6: El ORM maduro

En 2013, con EF 6, Microsoft cerró un ciclo. Fue la versión más completa y robusta del «EF clásico«.

Pero había un gran “pero”: seguía atado a .NET Framework. Y el mundo estaba cambiando: empezaban a sonar fuerte cosas como .NET Core, Linux, Docker, y EF no podía seguirles el ritmo.

Nace EF Core

Microsoft decidió que era hora de un nuevo comienzo, así que crearon Entity Framework Core, una reescritura total del ORM, pensada para ser:

  • Multiplataforma
  • Modular
  • Ligera
  • Y compatible con .NET Core y .NET 5/6/7/8…

Eso sí, EF Core 1.0 era muy básico al principio. Muchas cosas del EF clásico no estaban (ni migraciones completas, ni lazy loading, ni group joins).

Pero con cada versión, la cosa mejoró:

Las versiones de EF Core:

  • EF Core 2.x: Más estabilidad, tipos complejos, mejoras en rendimiento.
  • EF Core 3.x: Reescritura de LINQ, cambios en la forma de generar SQL.
  • EF Core 5.0: Mejoras masivas y alineado con .NET 5.
  • EF Core 6.0: Primer LTS, más performance, más features.
  • EF Core 7.0 y 8.0: Integración profunda con .NET moderno, nuevas APIs, y un enfoque brutal en rendimiento.

Lo que comenzó como una batalla entre LINQ to SQL y EF terminó con un claro ganador: Entity Framework Core. Hoy es el ORM oficial y más completo de Microsoft, pensado para trabajar en cualquier plataforma, con cualquier motor, y en cualquier tipo de proyecto.

Clase

Ahora que ya sabes qué es Entity Framework Core, es momento de arremangarse y ver cómo se usa en la vida real.

Vamos a construir algo simple, paso a paso, para que veas el flujo completo.

¿Listo?

Primero, imaginemos que queremos construir una app para guardar libros. Sí, un clásico 🙂

Creamos dos clases: Autor y Libro.

// Models/Autor.cs
public class Autor
{
    public int Id { get; set; }
    public string Nombre { get; set; }
    public List<Libro> Libros { get; set; }
}
// Models/Libro.cs
public class Libro
{
    public int Id { get; set; }
    public string Titulo { get; set; }
    public int AutorId { get; set; }
    public Autor Autor { get; set; }
}

Contexto y Mapping

Ahora vamos a crear el contexto y mapear las propiedades de nuestras clases y las columnas de la tabla.

using Microsoft.EntityFrameworkCore;
using BibliotecaApp.Models;

namespace BibliotecaApp.Data
{
    public class BibliotecaContext : DbContext
    {
        public BibliotecaContext(DbContextOptions<BibliotecaContext> options)
            : base(options) { }

        public DbSet<Autor> Autores { get; set; }
        public DbSet<Libro> Libros { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            // Tabla: Autor
            modelBuilder.Entity<Autor>(entity =>
            {
                entity.ToTable("Autores");

                entity.HasKey(a => a.Id);

                entity.Property(a => a.Nombre)
                      .IsRequired()
                      .HasMaxLength(100);
            });

            // Tabla: Libro
            modelBuilder.Entity<Libro>(entity =>
            {
                entity.ToTable("Libros");

                entity.HasKey(l => l.Id);

                entity.Property(l => l.Titulo)
                      .IsRequired()
                      .HasMaxLength(200);

                entity.Property(l => l.AutorId)
                      .IsRequired();

                entity.HasOne(l => l.Autor)
                      .WithMany(a => a.Libros)
                      .HasForeignKey(l => l.AutorId)
                      .OnDelete(DeleteBehavior.Cascade); // Elimina libros al eliminar autor
            });
        }
    }
}

Entity Framework Core mapea las propiedades automáticamente siguiendo convenciones por defecto. Pero también puedes hacerlo de forma explícita como hemos visto en el ejemplo.

Por convención Entity Framework Core asume que cada clase pública se convierte en una tabla, y cada propiedad se convierte en una columna.

Configuración

Ahora vamos a configuración la conexión a la base de datos.

En este caso utilizaremos una base de datos del tipo Sqlite:

// Program.cs
using BibliotecaApp.Data;
using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);

// Configura SQLite
builder.Services.AddDbContext<BibliotecaContext>(options =>
    options.UseSqlite("Data Source=biblioteca.db"));

builder.Services.AddControllers();

var app = builder.Build();

app.MapControllers();
app.Run();

Controlador

Y ya por fin utilizaremos un controlador para crear una API para mostrarte el ejemplo:

// Controllers/LibrosController.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using BibliotecaApp.Data;
using BibliotecaApp.Models;

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

    public LibrosController(BibliotecaContext context)
    {
        _context = context;
    }

    [HttpGet]
    public async Task<ActionResult<IEnumerable<Libro>>> GetLibros()
    {
        return await _context.Libros.Include(l => l.Autor).ToListAsync();
    }

    [HttpPost]
    public async Task<ActionResult<Libro>> PostLibro(Libro libro)
    {
        _context.Libros.Add(libro);
        await _context.SaveChangesAsync();

        return CreatedAtAction(nameof(GetLibros), new { id = libro.Id }, libro);
    }
}

Conclusiones

Y bueno, ya llegamos al final.

En resumen, Entity Framework Core es como ese colega que te ahorra un montón de trabajo pesado.

¿Te imaginas tener que escribir manualmente todas las consultas SQL, manejar conexiones y preocuparte por cómo hablar con la base de datos? Con Entity Framework Core, todo eso pasa a segundo plano.

Es flexible, potente y se adapta tanto a proyectos pequeños como a aplicaciones empresariales.

Además, al ser multiplataforma y open source, no estás atado a Windows ni a soluciones cerradas. Puedes trabajar con SQLite, SQL Server, PostgreSQL y más, sin cambiar prácticamente nada de tu código.

Si estás desarrollando con C#, usar Entity Framework Core es casi un no-brainer. Te permite enfocarte en lo que realmente importa: la lógica de tu app, no los detalles aburridos del acceso a datos.

¿Ya lo estás usando? ¿O todavía te lo estás pensando? Dale una oportunidad, ¡quizás sea justo lo que necesitabas y no lo sabías!

¿Qué es un ORM?

Introducción

Hola,

¿Te ha pasado que estás escribiendo SQL puro y de pronto tu código parece más un hechizo de Harry Potter que algo fácil de mantener?

Sí, yo también he estado ahí.

Justo ahí es donde entra en juego un ORM.

Te cuento …

¿Qué es un ORM?

Empecemos por las siglas.

Las siglas ORM son la abreviatura de Object Relational Mapping.

Pues bien, un ORM es una librería/framework que nos permite trabajar con las tablas de nuestra de datos utilizando objetos.

Es decir, que te permite convertir datos entre un sistema orientado a objetos (como C#, Java, Python, etc.) y una base de datos relacional (como SQL Server, MySQL, PostgreSQL, etc.).

En vez de escribir directamente las consultas SQL, usamos clases y objetos en nuestro lenguaje de programación para crear, leer, actualizar y eliminar datos (CRUD) en la base de datos.

Los ORM más populares

Estos son los ORM más populares:

Conclusiones

En resumen: un ORM te ahorra tiempo, te evita errores y te permite enfocarte en lo que realmente importa… ¡crear cosas geniales!

Pues bien, hasta aquí la teoría.

En las próximas entradas veremos algunos de los ORMs más conocidos.

Saludos.

Fórmulas matemáticas en C#

Introducción

Hola,

¿Necesitas que el usuario o una configuración externa defina fórmulas que tu sistema pueda interpretar?

¿Necesitas evaluar condiciones o reglas sin codificarlas directamente?

¿Necesitas construir aplicaciones más flexibles (por ejemplo, sistemas de cotizaciones, reglas de negocio, filtros personalizados)?

¿Necesitas validaciones que cambian sin necesidad de recompilar?

Pues justamente vamos a ver como conseguir eso mismo en C#.

Librería de expresiones matemáticas

Pues bien, te presento a NCalc.

NCalc es una librería muy útil, que te permite evaluar expresiones matemáticas o lógicas escritas como cadenas de texto (strings) en tiempo de ejecución.

¿Qué tipo de expresiones soporta?

Esta es una pequeña lista de las expresiones más habituales que soporta NCalc:

  • Operaciones matemáticas básicas: +, -, *, /
  • Comparaciones: ==, !=, >, <
  • Operadores lógicos: and, or, not
  • Funciones matemáticas: Sin, Cos, Pow, etc.
  • Variables: Puedes reemplazar variables con valores en tiempo de ejecución
  • Funciones personalizadas: Puedes crear tus propias funciones

Si estas interesado en conocer más acerca de las funciones matemáticas disponibles, aquí puedes echarle una vistazo.

Ejemplo: variables

Vamos a ver un primer ejemplo de cómo integrarlo en nuestro código en C#.

En este primer ejemplo, vamos a ver la utilización de variables con NCalc.

using System;
using NCalc;

class Program
{
    static void Main()
    {
        // Definimos la expresión con variables
        string expresion = "precio * cantidad + impuesto";

        // Creamos la instancia del evaluador
        Expression e = new Expression(expresion);

        // Asignamos dinámicamente los valores de los parámetros
        e.Parameters["precio"] = 19.99;
        e.Parameters["cantidad"] = 3;
        e.Parameters["impuesto"] = 5.5;

        // Evaluamos la expresión
        var resultado = e.Evaluate();

        // Mostramos el resultado
        Console.WriteLine($"Resultado de la expresión: {resultado}");
    }
}

Como has visto, no tiene mucho secreto.

Ejemplo: funciones personalizadas

En este segundo ejemplo, vamos a ver como definir funciones personalizadas en C# para utilizar en nuestra expression:

using System;
using NCalc;

class Program
{
    static void Main()
    {
        string expresion = "getPrecio() * getCantidad() + getImpuesto()";

        Expression e = new Expression(expresion);

        // Definimos las funciones personalizadas
        e.EvaluateFunction += (name, args) =>
        {
            switch (name)
            {
                case "getPrecio":
                    args.Result = ObtenerPrecio();
                    break;
                case "getCantidad":
                    args.Result = ObtenerCantidad();
                    break;
                case "getImpuesto":
                    args.Result = CalcularImpuesto();
                    break;
            }
        };

        var resultado = e.Evaluate();
        Console.WriteLine($"Resultado de la expresión: {resultado}");
    }

    // Funciones que generan parámetros dinámicos
    static double ObtenerPrecio()
    {
        // Podría venir de una base de datos, API, etc.
        return 12.5;
    }

    static int ObtenerCantidad()
    {
        // Simulación de un valor calculado
        return DateTime.Now.Second % 5 + 1; // valor entre 1 y 5
    }

    static double CalcularImpuesto()
    {
        // Un cálculo dinámico o configuración externa
        return 3.75;
    }
}

Conclusiones

En resumen, si necesitas formulas personalizables en tu aplicación, NCalc puede ser un gran aliadao para ti.

Saludos.