# three locid. MinimalBlog - Наскільки простим може бути блог ASP. NET?

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

## Вступ

Якщо ви стежите за цим блогом, ви, можливо, помітили, що моя основна платформа... назвемо її "спроектованою" "з ентузіазмом." Бази даних PostgreSQL і векторні бази даних, семантичний і повнотекстовий пошук з індексами GIN, автоматичним перекладом на 14 мов, багатьма серфінговими службами, плануванням роботи Hangfire, метричними стандартами Promeus, серілогічним слідкуванням, взаємодією HTMX, усування власних пакунків з noget, і достатньо контейнерів Docker, щоб змусити корабель заздрити.

**Це цілком навмисно.** Цей сайт - це моя жива лабораторія, де я експериментую з технологіями, тестовими стратегіями, вимірюю характеристики швидкодії та будую придатні пакунки. *гадана* бути переінструктаженим, тому що саме так я вчуся: вирішенням проблем, яких більшість блогів насправді не мають, а потім пакувати ці рішення як бібліотеки з відкритим кодом, які можуть використовувати інші.

Але ось в чому справа: **Вам, мабуть, нічого з цього не потрібно для ведення блогу.**

Ось чому я створив **threelucid. MinimalBlog** - щоб побачити, що відбувається, коли ви позбуваєтеся всіх експериментів і зосередитесь на абсолютно важливих програмах. Немає бази даних. Без складності. Просто позначте файли у теці, що з' являються у мережі. Ось так виглядає блог, якщо ви не використовуєте його як лабораторію.

> ЗАУВАЖЕННЯ: ви можете прочитати в кінці статті посилання на джерело, я планую видати його як [Пакунок nuget](https://www.nuget.org/packages?q=mostlylucid&includeComputedFrameworks=true&prerel=true&sortby=relevance) як тільки я отримаю час, щоб переконатися, що він на 100% надійний, і він не є TOO жахливою (так що пошукайте статті для тестування k6 найближчим часом!).

[TOC]

## Філософія: Менше є

Весь проект розроблено навколо одного принципу: **зробити це просто**. Без бази даних, без трубопроводу для збирання, без оболонки JavaScript. Тільки ASP. NET 9. 0, Markdig для обробки з міткою і близько 500 рядків коду загалом.
ЗАУВАЖЕННЯ: Ви навіть можете зробити цей клієнт поруч, використовуючи подібні типи [markdown- it](https://github.com/markdown-it/markdown-it) а потім просто залишити статичну карту сайта сервера `.md` files і make it even SIMPLER but... well this is a ASP.NET blog (cana shose a ⇩).

## Структура проекту

Погляньмо, як організовано цей проект:

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

## Серце: Помітка внизу BlogService

Основою блогу є `MarkdownBlogService` Клас. Це на диво прості 120 рядків коду, які працюють над:

1. Читання файлів з каталогу з міткою
2. Аналіз метаданих (напис, категорії, дата оприлюднення)
3. Перетворення розмітки у HTML за допомогою Markdig
4. Зафіксовування всього у пам' яті

Ось як це працює:

### Завантаження дописів

Служба сканує налаштований каталог для `.md` файли і завантаження їх всіх у пам' ять:

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

Зверніть увагу на кмітливу фільтрацію: `Count(c => c == '.') == 1` що ми отримаємо лише основу. `.md` файли, не перекладені версії на зразок `post.ar.md` або `post.de.md` (якщо ви хочете додати переклади пізніше).

### Аналіз метаданих

Кожен файл з міткою має просту конвенцію:

```markdown
# Post Title

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

Your content here...
```

Обробник видобуває ці метадані за допомогою формальних виразів і AST Markdig:

```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")
    };
}
```

### Стратегія кешування

Кожен спосіб використання `IMemoryCache` щоб уникнути повторного читання і перевпорядкування файлів з кожного запиту:

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

Записи кешу мають 30- хвилинний просковзання і 2- годинний абсолютний термін. Просте, ефективне.

## Налаштування програми: Program.cs

Все налаштування програми складається лише з 43 рядків: Сторінок Razor, кешу пам' яті, кешу виводу, двох служб однотонів, статичних файлів і кінцевої точки XML- RPC. Все кешовано як однотони, оскільки нічого не змінюється, якщо не буде змінено файли.

## Інтерфейс користувача: прості сторінки Razor

UI - це чистий HTML, що виконується сервером. Немає JavaScript, немає HTMX, немає альпійських. js. Домівки - це дописи на домашній сторінці `@Html.Raw(post.HtmlContent)` з an `[OutputCache]` attribute для годинного кешування HTML. Загалом чотири сторінки, кожна з яких менша за 30 рядків.

## Стилінг: 55 рядків CSS

У всьому візуальному дизайні працює лише один файл CSS з 55 рядками. Програма використовує нетипові властивості CSS для того, щоб створювати чистий, темний вигляд GitHub- натхнений:

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

Без препроцесора. Без кроку збирання. Немає тисяч класів допоміжних програм. Просто чистий, придатний для читання CSS, який працює.

## Можливість бонуса: MetaWeblog API

Для авторів, які надають перевагу призначеному редакторам з маркуванням, на зразок [Markdown Monster](https://markdownmonster.west-wind.com/), Проект складається з повнофункціональної реалізації API MetaWeblog. Цей API XML- RPC дозволяє зовнішні редактори:

- Список дописів
- Створити дописи
- Редагування існуючих дописів
- Вилучити дописи
- Вивантажити зображення
- Отримати категорії

Реалізація в `MetaWeblogService.cs` і керує повним протоколом XML- RPC, аналізу запитів і створення відповідей. Це означає, що ви можете писати дописи вашого блогу у вашому улюбленому редакторі і оприлюднювати їх безпосередньо до вашого блогу.

## Налаштування

Увесь файл налаштувань складається лише з 14 рядків:

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

- `MarkdownPath` - там, де живуть ваші файли markdown
- `ImagesPath` - де зберігаються зображення
- `MetaWeblog` - реєстраційні дані для доступу до зовнішнього редактора

## Використання як пакунка NuGet

> Як згадувалося вище, SOON буде доступний, але ще не:)

Тепер блог доступний як пакунок NuGet, що робить тривіальним додавання до будь- якої програми ASP. NET:

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

Потім у Вашій `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();
```

Ось так - тільки два методи називають`AddMinimalBlog` і `UseMinimalBlog`) і ви маєте робочий блог.

## Як запустити проект зразку

Щоб запустити включений проект прикладу, виконайте команду:

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

Відвідати `http://localhost:5000` і ви побачите блог з позначенням файлів за вказаним шляхом.

## Створення вмісту

Для створення допису блогу:

1. Створити новий `.md` файл у налаштованому вами файлі `MarkdownPath`
2. Додати стандартні метадані:
   ```markdown
   # Your Post Title
   
   <!-- category -- YourCategory, AnotherCategory -->
   <datetime class="hidden">2024-11-30T12:00</datetime>
   
   Your content here...
   ```
3. Зберегти файл
4. Кеш закінчиться протягом 30 хвилин (або перезавантажить програму)

Щоб додати зображення, просто розташуйте їх у налаштованих вами зображеннях `ImagesPath` каталог і посилання на них у вашому markdown:

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

## Чого бракує (за призначенням)

Цей мінімальний блог навмисно не включає:

- **Коментарі** - За потреби використовувати службу з третьою частиною
- **Пошук** - Тримайте ваш вміст впорядкованим за категоріями
- **Мітки** - Категорії достатньо для маленьких блогів
- **RSS/ Atom** - Дуже просто додати, якщо потрібно.
- **Розпізнавання** - MetaWeblog API використовує лише базовий автентифікаційний інтерфейс
- **Аналітичні явища** - Якщо бажаєте, додайте фрагмент JavaScript
- **Оптимізація SEO** - Працює з базовими мета- мітками
- **Повторні зображення** - Переглядач ним керує
- **Перемикач темних/ освітлених тем** - Однієї теми достатньо

Всі ці можливості *можливе* щоб додати, але вони типово не включені, тому що більшість маленьких блогів їх не потребують.

## Символи швидкодії

Незважаючи на простоту, цей блог **швидкий**:

- **Кечування пам' яті** означає без вводу/ виводу файла після першого завантаження
- **Кечування виводу** означає не використовувати Razor після першого запиту
- **Немає бази даних** означає, що немає запиту над
- **Немає JavaScript** означає швидше завантаження сторінки
- **Простий CSS** означає мінімальна обробка таблиці стилів

Для невеличкого блогу середньостатистичного (до 1000 дописів) ця архітектура перевищитиме більшість платформ блогів з базою даних.

## Коли слід використовувати цей параметр/ повнофункціональний блог

Користування **В основному, minimalBlog** коли:

- Ви починаєте персональний блог
- У вас менше 500 постів.
- Вам не потрібно багато мов
- Ви хочете, щоб все було просто
- Вам зручно у позначенні файлів
- Ви просто хочете писати і публікувати

Використовувати **платформа з великими значеннями** коли:

- Ви використовуєте свій блог як **Лабораторія навчання** для нових технологій
- Ви хочете експериментувати з стратегіями впровадження, моніторингом та оптимізацією швидкодії
- Вам потрібні специфічні можливості, зокрема багатомовна підтримка, повнотекстовий пошук або коментарі
- Ви будуєте пакунки і потребуєте тестування у реальному світі
- Ви фіксуєте складні технічні реалізації
- Подорож будування платформи така ж цінна, як і зміст, в якому вона знаходиться.

## Виключення: простота як можливість

У сучасному світі для веб- розробки, типово, ми часто досягаємо складних рішень. Вам потрібен блог? Краще налаштувати базу даних, налаштуйте ORM, налаштуйте міграцію, додайте кешування, реалізацію пошуку, налаштування фонових завдань...

Але іноді простим рішенням є *праворуч* розв' язання проблеми. Більшість з них. МінімалBlog доводить, що ви можете будувати функціональну, швидку і придатну для збереження платформу блогів за допомогою:

- **342 рядки C# Description of a condition. Do not translate key words (# V1S #, # V1 #,)** (MackdownBlogService + MetaWeblogService + Program.cs)
- **~1220 рядків розмітки Razor** (4 сторінки)
- **55 рядків CSS**
- **1 Залежність від NuGet** (Марквиг)

Це **менше ніж 520 рядків коду загалом** для повної платформи для ведення блогів.

Проект слугує як функціональною платформою блогу, так і нагадуванням: перед додаванням складності запитайте себе, чи вона вам справді потрібна. Іноді у теці, де є багато файлів, є все, що вам потрібно.

Ви можете знайти повний код у [Каталог здебільшого minimalBlog](https://github.com/scottgal/mostlylucidweb/tree/main/Mostlylucid.MinimalBlog) Я випущу пакунок nuget, як тільки я буду задоволений кодом.

Счастливого блога!