Back to "MinimalBlog - ¿Qué tan simple puede ser realmente un blog de ASP.NET?"

This is a viewer only at the moment see the article on how this works.

To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk

This is a preview from the server running through my markdig pipeline

ASP.NET Blogging Markdown

MinimalBlog - ¿Qué tan simple puede ser realmente un blog de ASP.NET?

Monday, 01 December 2025

Introducción

Si has estado siguiendo este blog, es posible que hayas notado que mi principal plataforma de blogs es... vamos a llamarlo "entusiastamente diseñado". PostgreSQL Y bases de datos vectoriales, búsqueda semántica y de texto completo con índices GIN, traducción automatizada a 14 idiomas, múltiples servicios alojados, programación de trabajos Hangfire, métricas Prometheus, rastreo de Serilog, interacciones HTMX, usignear mis propios paquetes de pepitas, y suficientes contenedores Docker para hacer un barco celoso.

Eso es totalmente deliberado. Este sitio es mi laboratorio viviente - un parque de juegos donde experimento con tecnologías, estrategias de implementación de pruebas, medir las características de rendimiento, y construir paquetes reutilizables. Supuestamente para ser sobre-ingeniería porque así es como aprendo: resolviendo problemas que la mayoría de los blogs no tienen realmente, entonces empaquetando esas soluciones como bibliotecas de código abierto que otros pueden usar.

Pero esta es la cosa: Probablemente no necesitas nada de eso para publicar un blog.

Es por eso que creé mayormente lúcido.MinimalBlog - para mostrar lo que sucede cuando quitas toda la experimentación y te centras en lo esencial. No hay base de datos. No hay tuberías de compilación. No hay complejidad. Sólo marca los archivos en una carpeta, apareciendo en la web. Así es como se ve un blog cuando no lo estás usando como laboratorio.

NOTA: Ver el final del artículo para un enlace a la fuente, Planeo publicar esto como un paquete de pepitas tan pronto como tenga tiempo para asegurarme de que es 100% confiable y es perf no es demasiado horrible (así que busca artículos de prueba k6 pronto!).

La filosofía: Menos es más

Todo el proyecto está diseñado en torno a un principio: **Mantenlo sencillo.**Sólo ASP.NET 9.0, Markdig para análisis de marcos, y alrededor de 500 líneas de código total. NOTA: Usted podría incluso hacer este lado del cliente mediante el uso de los gustos de markdown-it entonces sólo tiene el mapa del sitio del servidor estático .md archivos y lo hacen incluso SIMPLER pero... bueno, esto es un blog ASP.NET (kinda sorta ).

Estructura del proyecto

Veamos cómo se organiza el proyecto:

Mostlylucid.MinimalBlog/
├── Pages/
│   ├── Index.cshtml              # Homepage with post list
│   ├── Post.cshtml                # Individual post page
│   ├── Categories.cshtml          # List of all categories
│   ├── Category.cshtml            # Posts in a category
│   ├── _Layout.cshtml             # Shared layout
│   ├── _ViewImports.cshtml        # Shared imports
│   └── _ViewStart.cshtml          # Layout selection
├── wwwroot/
│   └── css/
│       └── site.css               # All the CSS you need
├── MarkdownBlogService.cs         # Core blog logic
├── MetaWeblogService.cs           # XML-RPC for external editors
├── Program.cs                     # Application setup
├── appsettings.json               # Configuration
└── Mostlylucid.MinimalBlog.csproj # Project file

El corazón: MarkdownBlogService

El meollo del blog es el MarkdownBlogService Es muy simple-sólo 120 líneas de código que manejan:

  1. Leyendo archivos de marcado desde un directorio
  2. Análisis de metadatos (título, categorías, fecha de publicación)
  3. Convertir markdown a HTML usando Markdig
  4. En caché de todo en la memoria

Así es como funciona:

Cargando publicaciones

El servicio escanea un directorio configurado para .md archivos y los carga a todos en la memoria:

private List<BlogPost> LoadAllPosts()
{
    if (!Directory.Exists(_markdownPath)) return [];

    return Directory.GetFiles(_markdownPath, "*.md", SearchOption.TopDirectoryOnly)
        .Where(f => Path.GetFileName(f).Count(c => c == '.') == 1) // Only base .md files
        .Select(ParseFile)
        .Where(p => p is { IsHidden: false })
        .OrderByDescending(p => p!.PublishedDate)
        .ToList()!;
}

Note el filtrado inteligente: Count(c => c == '.') == 1 asegura que sólo consigamos base .md archivos, no versiones traducidas como post.ar.md o post.de.md (en caso de que desee añadir traducciones más adelante).

Análisis de metadatos

Cada archivo Markdown sigue una simple convención:

# Post Title




Your content here...

El analizador extrae estos metadatos usando expresiones regulares y el Markdig AST:

private BlogPost? ParseFile(string filePath)
{
    var markdown = File.ReadAllText(filePath);
    var slug = Path.GetFileNameWithoutExtension(filePath);
    var document = Markdown.Parse(markdown, _pipeline);

    // Extract title from first H1
    var title = document.Descendants<HeadingBlock>()
        .FirstOrDefault(h => h.Level == 1)?
        .Inline?.FirstChild?.ToString() ?? slug;

    // Extract categories: 
    var categoryMatch = CategoryRegex().Match(markdown);
    var categories = categoryMatch.Success
        ? categoryMatch.Groups[1].Value.Split(',', StringSplitOptions.TrimEntries)
        : [];

    // Extract date: 
    var dateMatch = DateTimeRegex().Match(markdown);
    var publishedDate = dateMatch.Success && DateTime.TryParse(dateMatch.Groups[1].Value, out var dt)
        ? dt : File.GetCreationTimeUtc(filePath);

    return new BlogPost
    {
        Slug = slug,
        Title = title,
        Categories = categories,
        PublishedDate = publishedDate,
        HtmlContent = Markdown.ToHtml(markdown, _pipeline),
        IsHidden = markdown.Contains("<hidden")
    };
}

Estrategia de caché

Cada método en el servicio utiliza IMemoryCache para evitar releer y volver a analizar archivos en cada solicitud:

public IReadOnlyList<BlogPost> GetAllPosts()
{
    return cache.GetOrCreate("all_posts", entry =>
    {
        entry.SetOptions(CacheOptions);
        return LoadAllPosts();
    }) ?? [];
}

Las entradas de caché tienen un vencimiento deslizante de 30 minutos y 2 horas de caducidad absoluta. Simple, efectivo.

Configuración de la aplicación: Program.cs

Toda la configuración de la aplicación es de 43 líneas: Páginas Razor, caché de memoria, caché de salida, dos servicios singleton, servicio de archivos estáticos y un endpoint XML-RPC de MetaWeblog. Todo en caché como singletons porque nada cambia a menos que se modifiquen los archivos.

La interfaz de usuario: Páginas de rasguños simples

La interfaz de usuario es HTML puro renderizado por el servidor. No JavaScript, no HTMX, no Alpine.js. @Html.Raw(post.HtmlContent) con una [OutputCache] atributo para almacenamiento en caché HTML de una hora de duración. Cuatro páginas en total, cada una bajo 30 líneas.

Estilo: 55 líneas de CSS

Todo el diseño visual es manejado por un único archivo CSS con sólo 55 líneas. Utiliza propiedades personalizadas CSS para el tratamiento y crea un aspecto limpio, oscuro inspirado en GitHub:

:root {
  --bg: #0d1117;
  --bg-card: #161b22;
  --text: #c9d1d9;
  --text-muted: #8b949e;
  --accent: #58a6ff;
  --border: #30363d;
}

body {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  background: var(--bg);
  color: var(--text);
  line-height: 1.6;
  max-width: 48rem;
  margin: 0 auto;
  padding: 2rem 1rem;
}

/* ... more styles ... */

No hay preprocesador. No hay paso de construcción. No hay miles de clases de utilidad. Sólo CSS limpio, legible que funciona.

Característica de bonificación: API de MetaWeblog

Para los escritores que prefieren editores dedicados como Monstruo Markdown, el proyecto incluye una implementación completa de la API de MetaWeblog. Esta API XML-RPC permite a los editores externos:

  • Puestos incluidos en la lista
  • Crear nuevas publicaciones
  • Editar los puestos existentes
  • Suprímase la lista de puestos
  • Subir imágenes
  • Recuperar categorías

La aplicación está en MetaWeblogService.cs y maneja el protocolo XML-RPC completo, analizando solicitudes y generando respuestas. Esto significa que puedes escribir tus posts de blog en tu editor favorito y publicarlos directamente en tu blog.

Configuración

Todo el archivo de configuración es sólo 14 líneas:

{
  "MarkdownPath": "../Mostlylucid/Markdown",
  "ImagesPath": "wwwroot/images",
  "MetaWeblog": {
    "Username": "admin",
    "Password": "changeme",
    "BlogUrl": "http://localhost:5000"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information"
    }
  }
}
  • MarkdownPath - donde viven sus archivos Markdown
  • ImagesPath - donde se almacenan las imágenes
  • MetaWeblog - credenciales para el acceso externo al editor

Usar como un paquete NuGet

Como se ha mencionado anteriormente estará disponible SOON, pero aún no :)

El blog ya está disponible como un paquete NuGet, por lo que es trivial añadirlo a cualquier aplicación ASP.NET Core:

dotnet add package mostlylucid.MinimalBlog

Entonces en tu Program.cs:

builder.Services.AddRazorPages();
builder.Services.AddMinimalBlog(options =>
{
    options.MarkdownPath = "Markdown";
    options.ImagesPath = "wwwroot/images";
    options.EnableMetaWeblog = false; // Optional, defaults to true
});

var app = builder.Build();

app.UseStaticFiles();
app.UseMinimalBlog();
app.MapRazorPages();
app.Run();

Eso es todo - sólo dos llamadas de método (AddMinimalBlog y UseMinimalBlog) y tienes un blog de trabajo.

Ejecución del proyecto de la muestra

Para ejecutar el proyecto de muestra incluido:

cd Mostlylucid.MinimalBlog
dotnet run

Visita http://localhost:5000 y verás el blog con archivos Markdown desde la ruta configurada.

Crear contenido

Para crear un nuevo post de blog:

  1. Crear un nuevo .md archivo en su configurado MarkdownPath
  2. Añádanse los metadatos estándar:
    # Your Post Title
    
    
    
    
    Your content here...
    
  3. Guardar el archivo
  4. La caché expirará en 30 minutos (o reiniciará la aplicación)

Para añadir imágenes, simplemente colóquelas en su configurado ImagesPath y haga referencia a ellos en su marcado:

![Alt text](your-image.jpg)

Lo que falta (a propósito)

Este blog mínimo intencionalmente no incluye:

  • Observaciones - Utilizar un servicio de terceros si es necesario
  • Buscar - Mantenga su contenido organizado con categorías
  • Etiquetas - Las categorías son suficientes para blogs pequeños
  • RSS/Atom - Simple de añadir si lo necesitas
  • Autenticación - La API de MetaWeblog sólo utiliza la autenticación básica
  • Análisis - Añadir fragmento de JavaScript si lo desea
  • Optimización SEO - Funciona bien con metaetiquetas básicas
  • Imágenes responsivas - El navegador lo maneja.
  • Conmutador de tema oscuro/luz - Un tema es suficiente

Estas características son todas posible para agregar, pero no están incluidos por defecto porque la mayoría de los blogs pequeños no los necesitan.

Características del rendimiento

A pesar de su simplicidad, este blog es rápido:

  • Caché de memoria significa que no hay archivo E/S después de la primera carga
  • Caché de salida significa que no hay renderizado Razor después de la primera solicitud
  • No hay base de datos significa que no hay sobrecarga de la consulta
  • Sin JavaScript significa cargas de página más rápidas
  • Simple CSS significa un mínimo análisis de hoja de estilo

Para un blog pequeño a mediano (menos de 1000 publicaciones), esta arquitectura superará a la mayoría de las plataformas de blogs respaldadas por bases de datos.

Cuándo usar esto vs. el blog completo de la mayoría de los lúcidos

Uso Principalmente lúcido.MinimalBlog cuando:

  • Estás empezando un blog personal
  • Usted tiene menos de 500 puestos
  • No necesitas varios idiomas
  • Quieres que las cosas sean simples.
  • Te sientes cómodo con los archivos Markdown.
  • Sólo quieres escribir y publicar

Usar la Plataforma de la mayoría de los lúcidos cuando:

  • Estás usando tu blog como un laboratorio de aprendizaje para las nuevas tecnologías
  • Quiere experimentar con estrategias de implementación, monitoreo y optimización de rendimiento
  • Necesita características específicas como soporte multilingüe, búsqueda de texto completo o comentarios
  • Estás construyendo paquetes y necesitas un banco de pruebas del mundo real.
  • Usted está documentando complejas implementaciones técnicas
  • El viaje de construcción de la plataforma es tan valioso como el contenido que alberga

Conclusión: La simplicidad como característica

En el mundo moderno del desarrollo web, a menudo alcanzamos soluciones complejas por defecto. ¿Necesita un blog? Mejor configurar una base de datos, configurar un ORM, configurar migraciones, añadir caché, implementar búsqueda, configurar trabajos de fondo...

Pero a veces la solución simple es la derecha MinimalBlog demuestra que usted puede construir una plataforma de blog funcional, rápida y mantenible con:

  • 342 líneas de C# (MarkdownBlogService + MetaWeblogService + Program.cs)
  • ~120 líneas de marcado Razor (4 páginas)
  • 55 líneas de CSS
  • 1 Dependencia de NuGet (Markdig)

Eso es. menos de 520 líneas de código total para una plataforma de blogs completa.

El proyecto sirve como una plataforma de blog funcional y un recordatorio: antes de añadir complejidad, pregúntate si realmente lo necesitas. A veces una carpeta llena de archivos Markdown es todo lo que necesitas.

Puede encontrar el código fuente completo en el Principalmentelucid.MinimalBlog directorio Voy a lanzar el paquete de pepitas tan pronto como esté contento con el código.

¡Feliz blogueo!

logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.