# enimmäkseen lucid.MinimalBlog - How Simple Can an ASP.NET Blog Really Be?

<!--category-- ASP.NET, Markdown, Blogging -->
<datetime class="hidden">2025-12-01T12:00</datetime>

## Johdanto

Jos olet seurannut tätä blogia, olet saattanut huomata, että tärkein bloggausalustani on... Kutsutaan sitä "innostusti suunnitelluksi". PostgreSQL JA vektoritietokannat, semanttinen JA täystekstihaku GIN-hakemistoilla, automaattinen käännös 14 kielelle, useita isäntäpalveluita, Hagfire-työn aikataulutus, Prometheus-mittarit, Serilog-jäljitys, HTMX-vuorovaikutus, omien nuget-pakettien käyttö ja tarpeeksi Docker-kontteja, jotta laivasta tulee mustasukkainen.

**Se on täysin tarkoituksellista.** Tämä sivusto on elävä laboratorioni - leikkikenttä, jossa kokeilen teknologioita, testien käyttöönottostrategioita, mittaan suoritusominaisuuksia ja rakennan uudelleenkäytettäviä paketteja. *oletettava* Olla ylimuokattu, koska niin opin: ratkomalla ongelmia, joita useimmilla blogeissa ei todellisuudessa ole, pakkaamalla ratkaisut avoimiksi kirjastoiksi, joita muut voivat käyttää.

Mutta asia on näin: **Et luultavasti tarvitse mitään sellaista blogin pitämiseen.**

Siksi minä loin **Enimmäkseen lucid.MinimalBlog** - näyttää, mitä tapahtuu, kun kaikki kokeilut poistetaan ja keskitytään olennaiseen. Ei tietokantaa. Ei rakenneputkea. Ei monimutkaisuutta. Vain kansioon merkittyjä tiedostoja, jotka näkyvät verkossa. Tältä blogi näyttää, kun sitä ei käytetä laboratoriona.

> HUOMAUTUS: Katso artikkelin lopusta linkin lähde, aion julkaista tämän [Nugettipaketti](https://www.nuget.org/packages?q=mostlylucid&includeComputedFrameworks=true&prerel=true&sortby=relevance) Heti kun ehdin varmistaa, että se on sataprosenttisen luotettava ja perf ei ole liian kamala ( joten etsi k6-testiartikkelit pian!).

[TOC]

## Filosofia: Vähemmän on enemmän

Koko projekti on suunniteltu yhden periaatteen varaan: **pidä asia yksinkertaisena**. Ei tietokantaa, ei rakennusputkea, ei Javascript-kehystä. Vain ASP.NET 9.0, Markdig markdown-käännöksestä ja noin 500 riviä koodia yhteensä.
HUOMAUTUS: Voit jopa tehdä tämän asiakkaan puolella käyttämällä kuten [markdown-it](https://github.com/markdown-it/markdown-it) sitten vain on palvelinsivuston kartta staattinen `.md` Tiedostot ja tehdä siitä jopa SIMPLER, mutta...no tämä on ASP.NET-blogi (jollain tavalla).

## Projektin rakenne

Katsotaanpa, miten projekti on järjestetty:

```
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
```

## Sydän: MarkdownBlogService

Blogin ydin on `MarkdownBlogService` Se on huomattavan yksinkertainen 120 riviä koodia, jotka käsittelevät:

1. Luetaan hakemiston markdown-tiedostoja
2. Jäsennysmetatiedot (otsikko, kategoriat, julkaisupäivä)
3. Muunnetaan markdown HTML:ksi Markdigin avulla
4. Kaiken muistaminen

Näin se toimii:

### Loading posts

Palvelu skannaa konfiguroidun hakemiston `.md` tiedostot ja lataa ne kaikki muistiin:

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

Huomaa ovela suodatus: `Count(c => c == '.') == 1` takaa, että saamme vain tukikohdan `.md` tiedostot, ei käännetyt versiot kuten `post.ar.md` tai `post.de.md` (Jos haluat lisätä käännökset myöhemmin).

### Jäsennetään metatietoja

Jokainen markdown-tiedosto noudattaa yksinkertaista käytäntöä:

```markdown
# Post Title

<!-- category -- Category1, Category2 -->
<datetime class="hidden">2024-11-30T12:00</datetime>

Your content here...
```

Jäsentäjä ammentaa tämän metadatan säännöllisillä lausekkeilla ja Markdig AST:lla:

```csharp
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: <!-- category -- Cat1, Cat2 -->
    var categoryMatch = CategoryRegex().Match(markdown);
    var categories = categoryMatch.Success
        ? categoryMatch.Groups[1].Value.Split(',', StringSplitOptions.TrimEntries)
        : [];

    // Extract date: <datetime class="hidden">2024-01-01T00:00</datetime>
    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")
    };
}
```

### Välimuististrategia

Palvelun jokainen menetelmä käyttää `IMemoryCache` Välttääksesi tiedostojen uudelleenlukemisen ja uudelleen jäsentelyn jokaisesta pyynnöstä:

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

Tauluissa on 30 minuutin liukuva käyttöaika ja 2 tunnin ehdoton käyttöaika. Yksinkertaista, tehokasta.

## Sovelluksen asetukset: Program.cs

Koko sovellusasetus on vain 43 riviä: Razor-sivut, muistivälimuisti, lähtövälimuisti, kaksi singleton-palvelua, staattinen tiedostopalvelu ja MetaWeblog XML-RPC-päätetapahtuma. Kaikki välimuistit ovat singletoneja, koska mikään ei muutu, ellei tiedostoja muokata.

## The UI: Yksinkertaiset Razor-sivut

UI on silkkaa palvelimen renderöimää HTML:ää. Ei JavaScriptia, ei HTMX:ää, ei alppi.js:iä. `@Html.Raw(post.HtmlContent)` jossa on `[OutputCache]` Attribuutti tunnin mittaiselle HTML-välilyönnille. Neljä sivua yhteensä, kukin alle 30 riviä.

## Styling: 55 CSS:n riviä

Koko visuaalista muotoilua käsittelee yksi CSS-tiedosto, jossa on vain 55 riviä. Se käyttää CSS-ominaisuuksia teemailuun ja luo puhtaan, tumman GitHub-vaikutteisen ilmeen:

```css
: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 ... */
```

Ei esiprosessoria, ei rakennusvaihetta, ei tuhansia apuohjelmia, vain puhdasta, luettavaa CSS:ää, joka toimii.

## Bonusominaisuus: MetaWeblog API

Kirjailijoille, jotka pitävät enemmän omista markown-toimittajista [Markdown-hirviö](https://markdownmonster.west-wind.com/)Projekti sisältää täyden MetaWeblog API -toteutuksen. XML-RPC API:n avulla ulkoiset toimittajat voivat:

- Listatoimet
- Luo uusia virkoja
- Muokkaa olemassa olevia virkoja
- Poista virat
- Lähetä kuvia
- Hae luokat

Toteuttaminen on `MetaWeblogService.cs` Tämä tarkoittaa, että voit kirjoittaa blogikirjoituksesi suosikkieditoriisi ja julkaista ne suoraan blogiisi.

## Asetukset

Koko asetustiedosto on vain 14 riviä:

```json
{
  "MarkdownPath": "../Mostlylucid/Markdown",
  "ImagesPath": "wwwroot/images",
  "MetaWeblog": {
    "Username": "admin",
    "Password": "changeme",
    "BlogUrl": "http://localhost:5000"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information"
    }
  }
}
```

- `MarkdownPath` - missä markdown-tiedostosi asuvat
- `ImagesPath` - jossa kuvia säilytetään
- `MetaWeblog` - valtakirjat ulkoiseen editoriin

## NuGet-pakettina

> Kuten edellä mainittiin, SOON on saatavilla, mutta ei vielä :)

Blogi on nyt saatavilla NuGet-pakettina, joten ASP.NET Core -sovelluksen lisääminen on vähäpätöistä:

```bash
dotnet add package mostlylucid.MinimalBlog
```

Sitten sinun `Program.cs`:

```csharp
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();
```

Siinä kaikki - vain kaksi metodipuhelua (`AddMinimalBlog` sekä `UseMinimalBlog`) ja sinulla on työblogi.

## Näyteprojektin toteuttaminen

Mukana olevan näyteprojektin suorittaminen:

```bash
cd Mostlylucid.MinimalBlog
dotnet run
```

Vierailu `http://localhost:5000` Ja näet blogin merkittyjen polkujen markown-tiedostojen kera.

## Sisällön luominen

Luodaksesi uuden blogikirjoituksen:

1. Luo uusi `.md` tiedosto konfiguroidussa muodossa `MarkdownPath`
2. Lisää vakiometatiedot:
   ```markdown
   # Your Post Title
   
   <!-- category -- YourCategory, AnotherCategory -->
   <datetime class="hidden">2024-11-30T12:00</datetime>
   
   Your content here...
   ```
3. Tallenna tiedosto
4. Välimuisti päättyy 30 minuutin kuluessa (tai käynnistää sovelluksen uudelleen)

Lisää kuvia vain asetuksillasi `ImagesPath` Hakemisto ja viitteet maaliin:

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

## Mikä puuttuu (tarkoitus)

Tämä minimaalinen blogi ei tarkoituksellisesti sisällä:

- **Huomautukset** - Käytä tarvittaessa kolmannen osapuolen palvelua
- **Etsi** - Pidä sisältösi järjestettynä kategorioilla
- **Tunnisteet** - Luokat riittävät pieniin blogeihin
- **RSS/Atom** - Helppo lisätä, jos tarvitset sitä
- **Todentaminen** - MetaWeblog API käyttää vain perusauthia
- **Analyytikot** - Lisää Javascript, jos haluat
- **SEO-optimointi** - Toimii hyvin perusmetatunnisteiden kanssa
- **Vastaavia kuvia** - Selain hoitaa sen
- **Pimeä/kevyt teemayhdistelmä** - Yksi teema riittää

Nämä ominaisuudet ovat kaikki *mahdollinen* Lisään, mutta ne eivät ole mukana oletuksena, koska suurin osa pienistä blogeista ei tarvitse niitä.

## Suorituskykyä koskevat ominaisuudet

Yksinkertaisuudestaan huolimatta tämä blogi on **nopea**:

- **Muistin välilyönti** tarkoittaa, ettei tiedosto I/O ensimmäisen latauksen jälkeen
- **Tuotosvälitys** tarkoittaa ei Razor renderöintiä ensimmäisen pyynnön jälkeen
- **Ei tietokantaa** tarkoittaa, että ei kyselyä yläpuolella
- **Ei JavaScriptia** tarkoittaa nopeampaa sivukuormaa
- **Yksinkertainen CSS** tarkoittaa minimaalista tyylisivun kääntöä

Pienelle tai keskisuurelle blogille (alle 1000 viestiä) tämä arkkitehtuuri päihittää useimmat tietokannan tukemat blogialustat.

## Milloin käyttää tätä vs. täysi enemmistöblogi

Käyttö **Enimmäkseen lucid.MinimalBlog** kun:

- Aloitat henkilökohtaisen blogin
- Sinulla on alle 500 virkaa
- Et tarvitse useita kieliä
- Haluat pitää asiat yksinkertaisina
- Olet tyytyväinen markdown-tiedostoihin
- Haluat vain kirjoittaa ja julkaista

Käytä **täysi Enimmäkseen lusid-alusta** kun:

- Käytät blogiasi **oppimislaboratorio** uusille tekniikoille
- Haluat kokeilla käyttöönottostrategioita, seurantaa ja suorituskyvyn optimointia
- Tarvitset erityisominaisuuksia, kuten monikielistä tukea, kokotekstihakua tai kommentteja
- Rakennat paketteja ja tarvitset tosimaailman koekaniinin
- Dokumentoit monimutkaisia teknisiä toteutuksia
- Alustan rakennusmatka on yhtä arvokas kuin sen isännöimä sisältö

## Johtopäätös: Yksinkertaisuus ominaisuutena

Nykyaikaisessa verkkokehityksessä päädymme usein monimutkaisiin ratkaisuihin oletuksena. Tarvitsetko blogia? Parempi perustaa tietokanta, määrittää ORM, perustaa muuttoliikkeet, lisätä välimuistia, toteuttaa hakua, määrittää taustatyöpaikkoja...

Mutta joskus yksinkertainen ratkaisu on *oikea* Ratkaisu. Enimmäkseen lucid.MinimalBlog todistaa, että voit rakentaa toimivan, nopean ja ylläpidettävän blogialustan:

- **342 riviä C#:tä** (MarkdownBlogService + MetaWeblogService + Program.cs)
- **~120 riviä Razor-merkintää** (4 sivua)
- **55 riviä CSS:ää**
- **1 NuGet-riippuvuus** (Markdig)

Niin sitä pitää. **yhteensä vähemmän kuin 520 riviä koodia** täydelliselle bloggausalustalle.

Projekti toimii sekä toimivana blogialustana että muistutuksena: ennen kuin lisäät monimutkaisuutta, kysy itseltäsi, tarvitsetko sitä. Joskus tarvitset vain kansion, joka on täynnä markdown-tiedostoja.

Täydellisen lähdekoodin löydät osoitteesta [Enimmäkseen lucid.MinimalBlog-hakemisto](https://github.com/scottgal/mostlylucidweb/tree/main/Mostlylucid.MinimalBlog) Julkaisen Nuget-paketin heti, kun olen tyytyväinen koodiin.

Hyvää bloggausta!