Back to "MinimalBlog - Quanto può essere semplice un Blog 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 - Quanto può essere semplice un Blog ASP.NET?

Monday, 01 December 2025

Introduzione

Se stai seguendo questo blog, potresti aver notato che la mia principale piattaforma di blogging è... chiamiamolo "enthusiastically engineering." PostgreSQL E database vettoriali, ricerca semantica e full-text con indici GIN, traduzione automatica in 14 lingue, servizi ospitati multipli, programmazione dei lavori di Hangfire, metriche Prometheus, Serilog tracing, interazioni HTMX, utilizzo dei miei pacchetti di nuget e abbastanza contenitori Docker per rendere gelosa una nave.

E' del tutto intenzionale. Questo sito è il mio laboratorio vivente - un parco giochi dove sperimento tecnologie, strategie di test deployment, misuro le caratteristiche delle prestazioni e costruisco pacchetti riutilizzabili. supposta per essere eccessivamente ingegnerizzato perché è così che imparo: risolvendo i problemi che la maggior parte dei blog non hanno in realtà, quindi confezionando quelle soluzioni come librerie open-source altri possono utilizzare.

Ma il fatto e' questo: Probabilmente non hai bisogno di niente di tutto questo per gestire un blog.

E' per questo che ho creato Per lo piùlucid.MinimalBlog - mostrare cosa succede quando si toglie via tutta la sperimentazione e concentrarsi sull'essenziale assoluto. Nessun database. Nessuna pipeline build. Nessuna complessità. Basta marcare i file in una cartella, che appaiono sul web. Questo è come un blog quando non si sta utilizzando come un laboratorio.

NOTA: Vedere la fine dell'articolo per un link alla fonte, ho intenzione di rilasciare questo come un pacchetto nuget non appena ottengo il tempo per assicurarmi che sia affidabile al 100% e che il suo perf non sia troppo orribile (quindi cerca gli articoli di prova k6 presto!).

La filosofia: meno è di più

L'intero progetto è stato progettato attorno ad un unico principio: Semplice.. Nessun database, nessuna pipeline di compilazione, nessun framework JavaScript. Solo ASP.NET 9.0, Markdig per analisi di markdown, e circa 500 linee di codice totale. NOTA: Potete anche fare questo lato del client utilizzando i tipi di markdown-it quindi basta avere la mappa del sito del server statico .md files and make it even SIMPLER but...beh questo è un blog ASP.NET (un po 'un po').

Struttura del progetto

Vediamo come è organizzato il progetto:

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

Il cuore: MarkdownBlogService

Il cuore del blog è il MarkdownBlogService classe. E 'molto semplice-solo 120 linee di codice che gestiscono:

  1. Lettura dei file markdown da una directory
  2. Analisi dei metadati (titolo, categorie, data di pubblicazione)
  3. Conversione del markdown in HTML usando Markdig
  4. Caching tutto in memoria

Ecco come funziona:

Caricamento posta

Il servizio esegue la scansione di una directory configurata per .md file e li carica tutti in 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()!;
}

Notare il filtro intelligente: Count(c => c == '.') == 1 assicura che otteniamo solo la base .md file, non versioni tradotte come post.ar.md oppure post.de.md (nel caso in cui si desidera aggiungere traduzioni più tardi).

Analisi dei metadati

Ogni file markdown segue una semplice convenzione:

# Post Title




Your content here...

Il parser estrae questi metadati usando espressioni regolari e la 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")
    };
}

Caching Strategy

Ogni metodo utilizzato nel servizio IMemoryCache per evitare la rilettura e la rielaborazione dei file su ogni richiesta:

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

Le voci della cache hanno una scadenza scorrevole di 30 minuti e una scadenza assoluta di 2 ore. Semplice, efficace.

Impostazione applicazione: Program.cs

L'intera configurazione dell'applicazione è di sole 43 righe: Razor Pages, memory cache, output cache, due servizi singleton, servizio di file statico e un endpoint XML-RPC MetaWeblog. Tutto in cache come singleton perché nulla cambia a meno che i file non siano modificati.

L'interfaccia utente: Simple Razor Pages

L'interfaccia utente è pura HTML resa dal server. No JavaScript, no HTMX, no Alpine.js. La homepage elenca i messaggi, la pagina post renders @Html.Raw(post.HtmlContent) con [OutputCache] attributo per la cache HTML lunga un'ora. Quattro pagine totali, ciascuna sotto 30 righe.

Stile: 55 linee di CSS

L'intero design visivo è gestito da un unico file CSS con solo 55 linee. Utilizza le proprietà personalizzate CSS per loro e crea un look pulito e scuro ispirato a 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 ... */

Nessun preprocessore. Nessun passo di compilazione. Nessuna migliaia di classi di utilità. Solo CSS pulito e leggibile che funziona.

Caratteristica bonus: MetaWeblog API

Per gli scrittori che preferiscono redattori dedicati markdown come Mostro Markdown, il progetto include una completa implementazione MetaWeblog API. Questa API XML-RPC consente agli editor esterni di:

  • Messaggi elenco
  • Crea nuovi post
  • Modifica i messaggi esistenti
  • Elimina messaggi
  • Carica immagini
  • Recupera categorie

L'attuazione è in MetaWeblogService.cs e gestisce il protocollo XML-RPC completo, analizzando le richieste e generando risposte. Ciò significa che puoi scrivere i tuoi post sul blog nel tuo editor preferito e pubblicarli direttamente sul tuo blog.

Configurazione

L'intero file di configurazione è solo 14 righe:

{
  "MarkdownPath": "../Mostlylucid/Markdown",
  "ImagesPath": "wwwroot/images",
  "MetaWeblog": {
    "Username": "admin",
    "Password": "changeme",
    "BlogUrl": "http://localhost:5000"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information"
    }
  }
}
  • MarkdownPath - dove vivono i file markdown
  • ImagesPath - dove vengono memorizzate le immagini
  • MetaWeblog - credenziali per l'accesso esterno all'editor

Usare come pacchetto NuGet

Come detto sopra sarà presto disponibile ma non ancora:)

Il blog è ora disponibile come pacchetto NuGet, rendendo banale aggiungere a qualsiasi applicazione ASP.NET Core:

dotnet add package mostlylucid.MinimalBlog

Poi nella tua 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();

Questo è tutto - solo due chiamate metodo (AddMinimalBlog e UseMinimalBlog) e hai un blog di lavoro.

Esecuzione del progetto campione

Per eseguire il progetto campione incluso:

cd Mostlylucid.MinimalBlog
dotnet run

Visita http://localhost:5000 e vedrete il blog con i file markdown dal percorso configurato.

Creazione del contenuto

Per creare un nuovo post sul blog:

  1. Crea un nuovo .md file nel tuo file configurato MarkdownPath
  2. Aggiungi i metadati standard:
    # Your Post Title
    
    
    
    
    Your content here...
    
  3. Salva il file
  4. La cache scade entro 30 minuti (o riavvia l'app)

Per aggiungere immagini, basta inserirle nella configurazione ImagesPath directory e riferimento nel tuo markdown:

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

Cosa manca (a scopo)

Questo blog minimo intenzionalmente non include:

  • Osservazioni - Utilizzare un servizio di terze parti se necessario
  • Cerca - Mantenere il contenuto organizzato con le categorie
  • Etichette - Le categorie sono sufficienti per i piccoli blog
  • RSS/Atom - Semplice da aggiungere se ne hai bisogno
  • Autenticazione - MetaWeblog API utilizza solo auth di base
  • Analisi - Aggiungi snippet JavaScript se desiderato
  • Ottimizzazione SEO - Funziona bene con meta tag base
  • Immagini responsive - Lo gestisce il browser
  • Commuta tema scuro/luce - Basta un tema.

Queste caratteristiche sono tutte possibile per aggiungere, ma non sono inclusi per impostazione predefinita perché la maggior parte dei piccoli blog non hanno bisogno di loro.

Caratteristiche di prestazione

Nonostante la sua semplicità, questo blog è veloce:

  • Caching della memoria significa nessun file I/O dopo il primo caricamento
  • Caching di output significa nessuna resa del rasoio dopo la prima richiesta
  • Nessun database significa nessuna query in alto
  • Nessun JavaScript significa carichi di pagina più veloci
  • CSS semplice significa l'analisi minima del foglio di stile

Per un blog da piccolo a medio (sotto i 1000 post), questa architettura supererà la maggior parte delle piattaforme di blog supportate da database.

Quando usare questo contro il Blog per la maggior parte deilucidi

Uso Per lo più Lucid.MinimalBlog quando:

  • Stai iniziando un blog personale
  • Hai meno di 500 post
  • Non hai bisogno di più lingue
  • Vuoi che le cose rimangano semplici?
  • Sei a tuo agio con i file markdown
  • Vuoi solo scrivere e pubblicare

Utilizzare il piena piattaforma Mostlylucid quando:

  • Stai usando il tuo blog come laboratorio di apprendimento per le nuove tecnologie
  • Vuoi sperimentare strategie di distribuzione, monitoraggio e ottimizzazione delle prestazioni
  • Hai bisogno di caratteristiche specifiche come supporto multilingue, ricerca full-text, o commenti
  • Stai costruendo pacchetti e hai bisogno di un banco di prova del mondo reale
  • Stai documentando complesse implementazioni tecniche
  • Il viaggio di costruzione della piattaforma è prezioso quanto il contenuto che ospita

Conclusione: Semplicità come caratteristica

Nel moderno mondo di sviluppo web, spesso raggiungiamo soluzioni complesse per impostazione predefinita. Hai bisogno di un blog? Meglio impostare un database, configurare un ORM, impostare migrazioni, aggiungere cache, implementare la ricerca, configurare i lavori di background...

Ma a volte la soluzione semplice è il destra MinimalBlog dimostra che è possibile costruire una piattaforma blog funzionale, veloce e manutenibile con:

  • 342 linee di C# (MarkdownBlogService + MetaWeblogService + Program.cs)
  • ~120 linee di Razor markup (4 pagine)
  • 55 linee di CSS
  • 1 NuGet dipendenza (Markdig)

E' meno di 520 righe di codice totale per una piattaforma completa di blogging.

Il progetto serve sia come una piattaforma blog funzionale che come un promemoria: prima di aggiungere complessità, chiediti se ne hai davvero bisogno. A volte una cartella piena di file markdown è tutto ciò di cui hai bisogno.

È possibile trovare il codice sorgente completo nel Directory MinimalBlog del repository principale. Rilascerò il pacchetto nuget non appena sarò soddisfatto del codice.

Happy blogging!

logo

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