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
Monday, 01 December 2025
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!).
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 ).
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 meollo del blog es el MarkdownBlogService Es muy simple-sólo 120 líneas de código que manejan:
Así es como funciona:
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).
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")
};
}
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.
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 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.
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.
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:
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.
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 MarkdownImagesPath - donde se almacenan las imágenesMetaWeblog - credenciales para el acceso externo al editorComo 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.
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.
Para crear un nuevo post de blog:
.md archivo en su configurado MarkdownPath# Your Post Title
Your content here...
Para añadir imágenes, simplemente colóquelas en su configurado ImagesPath y haga referencia a ellos en su marcado:

Este blog mínimo intencionalmente no incluye:
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.
A pesar de su simplicidad, este blog es rápido:
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.
Uso Principalmente lúcido.MinimalBlog cuando:
Usar la Plataforma de la mayoría de los lúcidos cuando:
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:
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!
© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.