A modern, file-based blog system built with Blazor and .NET 10 that uses markdown files for content and SQLite for metadata caching.
✅ Markdown-Based: Write posts in Markdown with YAML front matter
✅ File-System Storage: No complex database - just upload markdown files
✅ SQLite Caching: Fast metadata queries with automatic indexing
✅ Theme System: Customizable themes with CSS, JavaScript, and configuration
✅ Advanced Markdown: Tables, code blocks, task lists, and more (via Markdig)
✅ Syntax Highlighting: Beautiful code highlighting with Highlight.js (10+ languages)
✅ SEO Optimized: Meta tags, Open Graph, Twitter Cards
✅ Responsive Design: Mobile-optimized layouts
✅ Animated Header: Theme-specific features like collapsing headers
✅ Tag System: Organize and filter posts by tags
✅ Pagination: Configurable posts per page
✅ View Tracking: Built-in analytics for post views
✅ Static File Serving: Images and documents served directly from post directories
✅ Placeholder Images: Auto-generated SVG placeholders for posts without cover images
✅ IIS Ready: Production-ready web.config included
- .NET 10 SDK or later
- Visual Studio 2022 or VS Code
- Clone the repository
- Open the solution in Visual Studio
- Press F5 to run
The blog will be available at https://localhost:5001
-
Create a directory in
BlogPosts/with format:YYYY-MM-DD-url-slugExample:BlogPosts/2024-11-15-my-first-post/ -
Create a
post.mdfile with YAML front matter:
---
title: "My First Post"
date: 2024-11-15
author: "Your Name"
summary: "A brief description of your post"
tags: [blazor, dotnet, tutorial]
image: "images/cover.jpg"
published: true
metaDescription: "SEO-friendly description"
metaKeywords: "blazor, markdown, blog"
---
# My First Post
Your markdown content here...
## Images

## Code Blocks
```csharp
public class Example
{
public string Name { get; set; }
}```
- Add images to
images/subdirectory (optional) - Restart the application to scan for new posts
MDBlog/
├── BlogPosts/ # Blog post storage (Git ignored)
│ ├── .gitkeep # Keeps directory in Git
│ ├── README.md # BlogPosts documentation
│ └── YYYY-MM-DD-post-slug/
│ ├── post.md # Markdown content
│ └── images/ # Post images
├── Components/
│ ├── Pages/
│ │ ├── BlogList.razor # Post listing with pagination
│ │ ├── BlogPostDetail.razor # Single post view
│ │ ├── BlogTag.razor # Tag filter view
│ │ ├── Home.razor # Home page
│ │ ├── Error.razor # Error handler
│ │ └── NotFound.razor # 404 handler
│ ├── Layout/
│ │ └── MainLayout.razor # Theme-aware layout
│ ├── App.razor # App root with dynamic theme loading
│ ├── Routes.razor # Routing configuration
│ └── _Imports.razor # Global usings
├── Data/
│ └── BlogDbContext.cs # SQLite database context
├── HostedServices/
│ └── BlogInitializationService.cs # Background post scanner
├── Models/
│ ├── BlogConfiguration.cs # Configuration model
│ ├── BlogPost.cs # Post entity
│ ├── PostMetadata.cs # YAML metadata
│ └── ThemeConfiguration.cs # Theme configuration model
├── Services/
│ ├── BlogPostService.cs # Post management service
│ └── ThemeService.cs # Theme loading service
├── Themes/ # Theme system
│ ├── Default/ # Default theme (included)
│ │ ├── theme.json
│ │ ├── theme.css
│ │ ├── theme.js
│ │ └── assets/images/
│ └── .gitkeep
├── wwwroot/
│ ├── css/
│ │ └── blog.css # Legacy styles
│ ├── js/
│ └── images/
│ └── blog-post-placeholder.svg # Fallback cover image
├── appsettings.json # Configuration (includes theme selection)
├── blog.db # SQLite database (auto-created, Git ignored)
├── web.config # IIS configuration
├── THEMES.md # Theme creation guide
└── README.md # This file
Edit appsettings.json to customize your blog:
{
"Blog": {
"PostsDirectory": "BlogPosts",
"PostsPerPage": 5,
"MarkdownFileName": "post.md",
"CacheDurationMinutes": 60,
"SiteName": "bitboxx.net",
"SiteDescription": "dotnetnuke blog, modules & more",
"Author": "Torsten Weggen",
"BaseUrl": "https://localhost:5001",
"Theme": "Default",
"ThemesDirectory": "Themes"
}
}MDBlog features a powerful theme system that allows you to customize your blog's appearance without modifying the core code.
Default Theme:
- Clean, minimal design
- Blue and white color scheme
- Professional appearance
- No JavaScript dependencies
- Perfect for generic blogs and documentation
Bitboxx Theme (Example):
- Matrix-inspired aesthetic
- Green (#00ff41) on dark background
- Collapsing header animation
- Scrolling ticker with recent posts
- Custom JavaScript features
- Perfect for tech blogs
Change the active theme in appsettings.json:
{
"Blog": {
"Theme": "Default", // or "Bitboxx" or "YourCustomTheme"
"ThemesDirectory": "Themes"
}
}Restart the application to apply the new theme.
Each theme is a self-contained directory:
Themes/
├── Default/ # Generic theme (included)
│ ├── theme.json # Theme configuration
│ ├── theme.css # Theme styles
│ ├── theme.js # Theme JavaScript (optional)
│ └── assets/ # Theme-specific assets
│ └── images/
└── YourTheme/ # Your custom theme
├── theme.json
├── theme.css
├── theme.js
└── assets/
See THEMES.md for comprehensive documentation on creating custom themes.
Quick start:
- Create theme directory:
mkdir -p Themes/MyTheme/assets/images- Create
theme.json:
{
"name": "My Theme",
"author": "Your Name",
"version": "1.0.0",
"header": {
"style": "Simple",
"height": 80
},
"javascript": {
"enabled": false
}
}-
Create
theme.csswith your styles -
Activate in
appsettings.json:
{
"Blog": {
"Theme": "MyTheme"
}
}Themes can customize:
- ✅ Colors - Primary, secondary, links, text
- ✅ Fonts - Body, headings, code blocks
- ✅ Layout - Header style, spacing, containers
- ✅ Components - Posts, tags, pagination, navigation
- ✅ JavaScript - Custom interactivity and animations
- ✅ Assets - Logos, backgrounds, custom images
Header Styles:
Simple- Clean, minimal headerMatrix- Animated header with effectsMinimal- Ultra-compact header
JavaScript Integration: Themes can include custom JavaScript for:
- Animated headers
- Scrolling effects
- Interactive components
- Custom navigation
Mobile Optimization: All themes include responsive breakpoints for:
- 📱 Mobile (≤768px)
- 💻 Tablet (769px-1024px)
- 🖥️ Desktop (>1024px)
For complete theme documentation, see THEMES.md.
Supported fields in markdown files:
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
title |
string | ✅ Yes | - | Post title |
date |
date | ❌ No | From directory name | Publication date |
author |
string | ❌ No | From config | Author name |
summary |
string | ❌ No | - | Brief excerpt for listings |
tags |
array | ❌ No | [] |
List of tags |
image |
string | ❌ No | - | Cover image path (relative) |
published |
boolean | ❌ No | true |
Visibility control |
metaDescription |
string | ❌ No | Summary | SEO meta description |
metaKeywords |
string | ❌ No | - | SEO keywords |
Post directories must follow: YYYY-MM-DD-url-slug
Examples:
2024-01-15-getting-started-with-blazor/2024-02-20-markdown-best-practices/2024-03-10-deploying-to-azure/
Benefits:
- 📅 Chronological sorting
- 🔗 URL-friendly slugs
- 🔍 SEO optimized
- 📂 Easy to manage
Use relative paths in your markdown:
The system automatically converts these to absolute URLs:
<img src="/BlogPosts/2024-11-15-my-post/images/photo.jpg" />Specify in YAML front matter:
image: "images/cover.jpg"If no image is specified, an auto-generated placeholder SVG is used.
BlogPosts/2024-11-15-my-post/
├── post.md
└── images/
├── cover.jpg # Cover image
├── photo1.png # Content images
└── photo2.jpg
Syntax highlighting is automatically applied to code blocks. Just specify the language:
public class Example
{
public string Name { get; set; }
}Supported languages:
- C# (
csharp) - JavaScript (
javascript) - TypeScript (
typescript) - Python (
python) - PowerShell (
powershell) - SQL (
sql) - JSON (
json) - XML (
xml) - HTML (
html) - CSS (
css) - And many more...
Theme: VS2015 Dark (customizable in App.razor)
MDBlog includes a powerful theme system with built-in themes:
Default Theme:
- Clean, professional appearance
- Blue (#007bff) and white colors
- Standard sans-serif fonts
- Mobile-optimized layout
- No JavaScript dependencies
- Perfect for business blogs and documentation
Bitboxx Theme:
- Matrix-inspired aesthetic
- Dark green (#00b82e) on light background
- Animated header that collapses on scroll (230px → 80px)
- Scrolling ticker showing recent posts
- Monospace fonts in header (Courier New)
- Custom JavaScript animations
- Perfect for tech blogs and retro aesthetics
Theme Switching:
Simply change "Theme": "Default" to "Theme": "Bitboxx" in appsettings.json and restart!
All themes are mobile-first with optimized layouts:
Desktop (>768px):
- Full-width headers with all features
- Spacious padding for comfortable reading
- Multi-column layouts where appropriate
Mobile (≤768px):
- Compact headers (collapsible in Bitboxx theme)
- Minimal padding to maximize content space
- Single-column layouts
- Touch-friendly navigation
Create your own themes to match your brand! See THEMES.md for:
- Theme structure and files
- Configuration options
- CSS guidelines
- JavaScript integration
- Responsive breakpoints
- Best practices
The SQLite database (blog.db) is automatically created on first run:
// In BlogInitializationService
await dbContext.Database.EnsureCreatedAsync();
await blogService.RefreshPostsFromFileSystemAsync();What's stored:
- Post metadata (title, date, author, tags, etc.)
- View counts
- Cache timestamps
Not stored:
- Markdown content (read from files on-demand)
- Images (served as static files)
You can safely delete blog.db anytime:
rm blog.db blog.db-shm blog.db-walIt will be regenerated on next startup! ✅
# SQLite database (auto-generated)
*.db
*.db-shm
*.db-wal
# Blog content (user content, not source code)
BlogPosts/
!BlogPosts/.gitkeep
!BlogPosts/README.md
# Build output
publish/Why?
- Database is regenerated from markdown files
- Blog posts are user content, managed separately
- Only source code is tracked in Git
Development:
git clone repo
# Add your own test posts
git add <source-files-only>
git commit -m "Feature"
# blog.db and BlogPosts/ are NOT committedProduction:
git pull
# Upload posts via FTP/rsync separately
dotnet publish
# blog.db created automatically from posts- Blazor - Interactive web UI framework
- .NET 10 - Runtime and libraries
- Markdig - Advanced Markdown processor
- Entity Framework Core - Database access layer
- SQLite - Lightweight database for metadata
- YamlDotNet - YAML front matter parsing
- Highlight.js - Syntax highlighting (CDN)
See IIS-DEPLOYMENT.md for detailed instructions.
Quick steps:
- Publish:
dotnet publish -c Release-
Deploy: Copy
publish/contents to IIS directory -
Configure IIS:
- Application pool: .NET 10
- Enable HTTPS
- Add
web.configtransformations if needed
- Start the site in IIS Manager
Your blog should now be live! 🌐
-
HTTP Error 500.30 - Failed to start Windows Process Activation Service (WAS)
- Solution: Ensure the correct .NET version is installed and assigned in IIS
-
404 Not Found for posts or assets
- Solution: Check routing in
Routes.razorand ensure posts exist inBlogPosts/
- Solution: Check routing in
-
Database file not found on startup
- Solution: Ensure
blog.dbis in the root directory and accessible
- Solution: Ensure
-
Theme not applying changes
- Solution: Restart the application after changing the theme in
appsettings.json
- Solution: Restart the application after changing the theme in
For more troubleshooting tips, see Troubleshooting.md in the docs folder.
1. How do I update MDBlog to the latest version?
- Pull the latest changes from the repository
- Update your NuGet packages to the latest versions
- Run migrations if there are any database changes
- Restart the application
2. Can I use my own domain name?
Yes! Configure your domain's DNS to point to your server's IP address, then update the BaseUrl in appsettings.json to match your domain.
3. How can I contribute to MDBlog?
We welcome contributions! Please fork the repository, make your changes, and submit a pull request. See CONTRIBUTING.md for more details.
4. Where can I find the documentation?
Documentation is available in the docs/ folder and online at MDBlog Docs.
For more FAQs, please refer to FAQ.md in the docs folder.
Let's get blogging! 📝