Back to "MinimalBlog - Πόσο απλό μπορεί να είναι ένα ASP.NET Blog πραγματικά;"

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 - Πόσο απλό μπορεί να είναι ένα ASP.NET Blog πραγματικά;

Monday, 01 December 2025

Εισαγωγή

Αν παρακολουθείτε αυτό το blog, θα μπορούσατε να έχετε παρατηρήσει ότι η κύρια πλατφόρμα blogging μου είναι... ας την ονομάσουμε "ενθουσιωδώς επεξεργασμένη." PostgreSQL ΚΑΙ διανυσματική βάση δεδομένων, σημασιολογική και πλήρης αναζήτηση με GIN ευρετήρια, αυτόματη μετάφραση σε 14 γλώσσες, πολλαπλές υπηρεσίες φιλοξενίας, προγραμματισμό εργασίας Hangfire, Prometheus μετρικές, Serilog ιχνηλάτηση, αλληλεπιδράσεις HTMX, usign own nuget πακέτα μου, και αρκετά δοχεία Docker για να κάνει ένα πλοίο ζηλιάρης.

Αυτό είναι εντελώς σκόπιμο. Αυτό το site είναι το ζωντανό μου εργαστήριο - μια παιδική χαρά όπου πειραματίζομαι με τεχνολογίες, στρατηγικές ανάπτυξης δοκιμών, μέτρα χαρακτηριστικά απόδοσης, και να χτίσει επαναχρησιμοποίητα πακέτα. Υποτίθεται ότι να είναι υπερ-σχεδιασμένες γιατί έτσι μαθαίνω: λύνοντας προβλήματα που τα περισσότερα blogs δεν έχουν στην πραγματικότητα, στη συνέχεια, συσκευάζοντας αυτές τις λύσεις ως ανοικτές βιβλιοθήκες άλλων μπορούν να χρησιμοποιήσουν.

Αλλά εδώ είναι το θέμα: Πιθανότατα δεν χρειάζεσαι τίποτα από αυτά για να διευθύνεις ένα blog.

Γι' αυτό δημιούργησα. ως επί το πλείστον διαυγής.minimalBlog - για να δείξει τι συμβαίνει όταν αφαιρέσετε όλα τα πειράματα και να επικεντρωθεί στα απολύτως απαραίτητα στοιχεία. Δεν βάση δεδομένων. Δεν κατασκευή αγωγού. Δεν πολυπλοκότητα. Απλά μαρκάρετε τα αρχεία σε ένα φάκελο, εμφανίζονται στο διαδίκτυο. Αυτό είναι ό, τι ένα blog μοιάζει με όταν δεν το χρησιμοποιείτε ως εργαστήριο.

ΣΗΜΕΙΩΣΗ: Δείτε το τέλος του άρθρου για ένα σύνδεσμο με την πηγή, σκοπεύω να κυκλοφορήσει αυτό ως ένα πακέτο nugetName Μόλις βρω χρόνο να εξασφαλίσω ότι είναι 100% αξιόπιστο και το perf δεν είναι πολύ απαίσιο (οπότε ψάξτε για άρθρα δοκιμών k6 σύντομα!).

Η Φιλοσοφία: Λιγότερα είναι περισσότερα

Ολόκληρο το έργο έχει σχεδιαστεί γύρω από μία αρχή: **Κράτα το απλό.**Ούτε βάση δεδομένων, ούτε αγωγός κατασκευής, ούτε πλαίσιο JavaScript. ΣΗΜΕΙΩΣΗ: Θα μπορούσατε να κάνετε ακόμη και αυτή την πλευρά του πελάτη με τη χρήση των likes του Markdown-it Στη συνέχεια, απλά να έχουν το χάρτη site διακομιστή στατικό .md files and make it even SIMPLER but...well this is a ASP.NET blog (kinda sorta

Δομή έργου

Ας δούμε πώς είναι οργανωμένο το έργο:

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

The Heart: MarkdownBlogService

Ο πυρήνας του blog είναι το MarkdownBlogService Είναι εξαιρετικά απλό-μόνο 120 γραμμές κώδικα που χειρίζονται:

  1. Ανάγνωση αρχείων markdown από έναν κατάλογο
  2. Ανάλυση μεταδεδομένα (τίτλος, κατηγορίες, ημερομηνία δημοσίευσης)
  3. Μετατροπή markdown σε HTML χρησιμοποιώντας Markdig
  4. Μαζεύοντας τα πάντα στη μνήμη

Ακούστε πώς λειτουργεί:

Φόρτωση θέσεων

Η υπηρεσία σαρώνει ένα ρυθμισμένο κατάλογο για .md αρχεία και τα φορτώνει όλα στη μνήμη:

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()!;
}

Προσέξτε το έξυπνο φίλτρο: Count(c => c == '.') == 1 εξασφαλίζει ότι θα πάρουμε μόνο τη βάση .md αρχεία, όχι μεταφρασμένες εκδόσεις όπως post.ar.md ή post.de.md (σε περίπτωση που θέλετε να προσθέσετε μεταφράσεις αργότερα).

Ανάλυση Μεταδεδομένα

Κάθε αρχείο markdown ακολουθεί μια απλή σύμβαση:

# Post Title




Your content here...

Ο αναλυτής εξάγει αυτό το μεταδεδομένα χρησιμοποιώντας τακτικές εκφράσεις και το 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")
    };
}

Στρατηγική σύλληψης

Κάθε μέθοδος στην υπηρεσία χρησιμοποιεί IMemoryCache για να αποφευχθεί η επαναδιαμόρφωση και η εκ νέου ανάλυση αρχείων σε κάθε αίτηση:

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

Καταχωρήσεις Cache έχουν 30 λεπτά συρόμενη λήξη και 2 ώρες απόλυτη λήξη. Απλό, αποτελεσματικό.

Ρύθμιση εφαρμογής: Program.cs

Ολόκληρη η εφαρμογή είναι μόλις 43 γραμμές: Razor Pages, μνήμη κρύπτη, κρύπτη εξόδου, δύο υπηρεσίες singleton, στατικό αρχείο σερβίρει, και ένα τελικό σημείο MetaWeblog XML-RPC.

The UI: Απλό Razor Pages

Το UI είναι καθαρό server-reded HTML. No JavaScript, no HTMX, no Alpine.js. The homepage lists posts, the post page renders @Html.Raw(post.HtmlContent) με [OutputCache] 4 σελίδες συνολικά, η κάθε μία κάτω από 30 γραμμές.

Στυλ: 55 Γραμμές CSS

Ολόκληρο το οπτικό σχέδιο αντιμετωπίζεται από ένα ενιαίο αρχείο CSS με μόλις 55 γραμμές. Χρησιμοποιεί CSS προσαρμοσμένες ιδιότητες για να τους και δημιουργεί ένα καθαρό, σκούρο 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 ... */

Χωρίς προεπεξεργαστή, χωρίς βήμα κατασκευής, χωρίς χιλιάδες μαθήματα χρησιμότητας, μόνο καθαρά, ευανάγνωστα CSS που λειτουργούν.

Μπόνους Χαρακτηριστικό: MetaWeblog API

Για συγγραφείς που προτιμούν αφοσιωμένους αρχισυντάκτες όπως ο Markdown Markdown Monster, το έργο περιλαμβάνει μια πλήρη εφαρμογή MetaWeblog API. Αυτό το XML-RPC API επιτρέπει σε εξωτερικούς επεξεργαστές:

  • Θέσεις λίστας
  • Δημιουργία νέων θέσεων
  • Επεξεργασία υφιστάμενων θέσεων
  • Διαγραφή θέσεων
  • Ανεβάστε εικόνες
  • Κατηγορίες ανάκτησης

Η εφαρμογή της MetaWeblogService.cs και χειρίζεται το πλήρες πρωτόκολλο XML-RPC, ανάλυση αιτήσεων και τη δημιουργία απαντήσεων. Αυτό σημαίνει ότι μπορείτε να γράψετε τις δημοσιεύσεις blog σας στο αγαπημένο σας επεξεργαστή και να τις δημοσιεύσετε απευθείας στο blog σας.

Ρύθμιση

Ολόκληρο το αρχείο ρυθμίσεων είναι μόλις 14 γραμμές:

{
  "MarkdownPath": "../Mostlylucid/Markdown",
  "ImagesPath": "wwwroot/images",
  "MetaWeblog": {
    "Username": "admin",
    "Password": "changeme",
    "BlogUrl": "http://localhost:5000"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information"
    }
  }
}
  • MarkdownPath - όπου τα αρχεία σας markdown ζουν
  • ImagesPath - όπου αποθηκεύονται οι εικόνες
  • MetaWeblog - διαπιστευτήρια για εξωτερική πρόσβαση επεξεργαστή

Χρήση ως πακέτο NuGet

Όπως αναφέρθηκε παραπάνω θα είναι σύντομα διαθέσιμο αλλά όχι ακόμα :)

Το blog είναι τώρα διαθέσιμο ως ένα πακέτο NuGet, καθιστώντας ασήμαντο να προσθέσετε σε οποιαδήποτε εφαρμογή ASP.NET Core:

dotnet add package mostlylucid.MinimalBlog

Στη συνέχεια, σε σας 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();

Αυτό είναι - μόνο δύο κλήσεις μεθόδου (AddMinimalBlog και UseMinimalBlog) and you have a working blog.

Εκτέλεση του δείγματος έργου

Για την εκτέλεση του συμπεριλαμβανομένου δείγματος έργου:

cd Mostlylucid.MinimalBlog
dotnet run

Επίσκεψη http://localhost:5000 και θα δείτε το blog με τα αρχεία Markdown από το ρυθμισμένο μονοπάτι.

Δημιουργία Περιεχομένου

Για να δημιουργήσετε ένα νέο blog post:

  1. Δημιουργία ενός νέου .md αρχείο στο ρυθμισμένο σας MarkdownPath
  2. Προσθέστε τα τυποποιημένα μεταδεδομένα:
    # Your Post Title
    
    
    
    
    Your content here...
    
  3. Αποθήκευση αρχείου
  4. Η κρύπτη λήγει εντός 30 λεπτών (ή επανεκκίνηση της εφαρμογής)

Για να προσθέσετε εικόνες, απλά τοποθετήστε τις στη ρυθμισμένη σας ImagesPath directory and refer them in your markdown:

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

Τι Λείπει (Στόχος)

Αυτό το minimal blog σκόπιμα δεν περιλαμβάνει:

  • Σχόλια - Χρησιμοποίησε μια υπηρεσία τρίτων, αν χρειαστεί
  • Αναζήτηση - Κρατήστε το περιεχόμενό σας οργανωμένο με κατηγορίες
  • Ετικέτες - Οι κατηγορίες είναι αρκετές για μικρά blogs
  • RSS/AtomCity name (optional, probably does not need a translation) - Απλά να προσθέσετε αν το χρειάζεστε
  • Ταυτοποίηση - Το MetaWeblog API χρησιμοποιεί μόνο βασικό auth
  • Analytics - Προσθήκη JavaScript snippet αν επιθυμείτε
  • Βελτιστοποίηση SEO - Λειτουργεί μια χαρά με βασικές meta tags
  • Αντιδραστικές εικόνες - Ο περιηγητής το χειρίζεται.
  • Σκούρο / ελαφρύ θέμα εναλλαγή - Ένα θέμα είναι αρκετό.

Αυτά τα χαρακτηριστικά είναι όλα Πιθανό για να προσθέσετε, αλλά δεν περιλαμβάνονται εξ ορισμού επειδή τα περισσότερα μικρά blogs δεν τα χρειάζονται.

Χαρακτηριστικά επιδόσεων

Παρά την απλότητά του, αυτό το blog είναι Γρήγορα.:

  • Κρυπτογράφηση μνήμης σημαίνει ότι δεν υπάρχει αρχείο I/O μετά το πρώτο φορτίο
  • Φύλαξη εξόδου σημαίνει καμία απόδοση Razor μετά το πρώτο αίτημα
  • Καμία βάση δεδομένων Σημαίνει ότι δεν υπάρχει ερώτηση από πάνω.
  • Δεν JavaScript σημαίνει γρηγορότερα φορτία σελίδων
  • Απλή CSS σημαίνει minimal style sheet parsing

Για ένα μικρό έως μεσαίο blog (κάτω από 1000 δημοσιεύσεις), αυτή η αρχιτεκτονική θα ξεπεράσει τις περισσότερες πλατφόρμες blog που υποστηρίζονται από τη βάση δεδομένων.

Πότε να χρησιμοποιήσετε αυτό vs. το πλήρες πιο διαυγή blog

Χρήση Κυρίως διαυγής. MinimalBlog όταν:

  • Ξεκινάς ένα προσωπικό blog
  • Έχετε λιγότερες από 500 θέσεις
  • Δεν χρειάζεσαι πολλές γλώσσες.
  • Θέλεις να κρατήσεις τα πράγματα απλά
  • Είσαι άνετα με τα αρχεία Markdown
  • Θέλεις απλά να γράψεις και να δημοσιεύσεις

Χρήση του Πλήρως διαυγής πλατφόρμα όταν:

  • Χρησιμοποιείτε το blog σας ως ένα Εργαστήριο εκμάθησης για νέες τεχνολογίες
  • Θέλετε να πειραματιστείτε με στρατηγικές ανάπτυξης, παρακολούθηση, και βελτιστοποίηση των επιδόσεων
  • Χρειάζεστε συγκεκριμένα χαρακτηριστικά όπως πολύγλωσση υποστήριξη, αναζήτηση πλήρους κειμένου, ή σχόλια
  • Φτιάχνεις πακέτα και χρειάζεσαι ένα αληθινό κρεβάτι.
  • Καταγράφετε περίπλοκες τεχνικές εφαρμογές.
  • Το ταξίδι της κατασκευής της πλατφόρμας είναι τόσο πολύτιμο όσο το περιεχόμενο που φιλοξενεί

Συμπέρασμα: Απλότητα ως Χαρακτηριστικό

Στον σύγχρονο κόσμο ανάπτυξης ιστοσελίδων, συχνά προσπαθούμε να βρούμε πολύπλοκες λύσεις εξ ορισμού. Χρειάζεστε ένα blog; Καλύτερα να δημιουργήσετε μια βάση δεδομένων, να ρυθμίσετε ένα ORM, να ρυθμίσετε τις μεταναστεύσεις, να προσθέσετε caching, να εφαρμόσετε την αναζήτηση, να ρυθμίσετε τις δουλειές υποβάθρου...

Αλλά μερικές φορές η απλή λύση είναι η Δεξιά λύση. Κυρίως διαυγής.MinimalBlog αποδεικνύει ότι μπορείτε να οικοδομήσετε μια λειτουργική, γρήγορη και συντηρήσιμη πλατφόρμα blog με:

  • 342 γραμμές του C# (MarkdownBlogService + MetaWeblogService + Program.cs)
  • ~120 γραμμές του Razor markup (4 σελίδες)
  • 55 γραμμές του CSS
  • 1 NuGet εξάρτηση (Markdig)

Αυτό είναι λιγότερο από 520 γραμμές του συνόλου κωδικών για μια πλήρη πλατφόρμα blogging.

Το έργο χρησιμεύει και ως μια λειτουργική πλατφόρμα blog και μια υπενθύμιση: πριν προσθέσετε πολυπλοκότητα, ρωτήστε τον εαυτό σας αν το χρειάζεστε πραγματικά. Μερικές φορές ένας φάκελος γεμάτος αρχεία markdown είναι το μόνο που χρειάζεστε.

Μπορείτε να βρείτε τον πλήρη πηγαίο κώδικα στο Κυρίως διαυγής.MinimalBlog κατάλογος Θα ελευθερώσω το πακέτο μόλις είμαι ευχαριστημένος με τον κωδικό.

Καλό blogging!

logo

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