Pegasus

ASP.NET Core Blog Engine

jarallax-cover

Pegasus 🦄 is an awesome blog engine written in C#, built with .NET 9, ASP.NET Core, and Angular. I built it myself, it's my baby. If you're interested in learning more about it, continue reading.

Features

Here's a high-level overview of the core features.

Categories

Pegasus supports flat categories, posts can be assigned to multiple categories at a time.

Tags

You can define as many tags as you like. Posts can have multiple tags too.

Posts

Blog posts are written in HTML, using TinyMCE as the editor. You can configure the following for each post.

Published date and time

Posts can be back-dated to whatever date and time you like.

Status & visibility

  • Draft/Published
  • Private/Public
  • Featured

Permalink

The URL slug for each post. You can leave it blank and have it generated from the title, or you can choose whatever you like.

Metadata

The meta description used for SEO, RSS feeds, etc.

Categories

You can select categories from a check list, or add new ones on the fly.

Tags

You can select tags from an autocomplete list, or add new ones on the fly.

Cover image

Each post is required to have a cover image. This ensures a consistent layout and proper SEO data.
You can upload your own image, or enter a URL. Fallback directives apply a placeholder to broken images.

Comments

Allow comments (if turned off, comments and replies won't be accepted).

User comments are stored in-house in the database, supporting a hierarchical structure. I wanted user comments to be part of the database, but you could easily turn it off and use something else like Disqus. Comments are written in HTML too, using TinyMCE as the editor, but only support a subset of editing features. By default, comments need moderation before they go live. You can manage comments in the admin dashboard.

Article Series

Pegasus implements article series for managing multi-part articles.
You can create article series, assign posts to them, reorder the series and their parts via a user-friendly UI.
Smart navigation controls and UI components are implemented for easy discovery and user engagement.

Search

Search through articles, categories, and tags.
Pegasus implements a paginated search function that uses relevance scoring for more accurate and helpful results.

Feeds

The blog feed is available in RSS. Additionally, each category and tag has an RSS feed. There's also an OPML feed, look here for more information. An XML sitemap is generated too, mainly for search engines, but could be used for other needs as well.

Export/Import

You can export the data to an XML file, or a Zip archive. The zip archive includes the XML file, plus the images folder (cover and in-post images). The import feature allows you to upload the XML file or the Zip archive. One good thing about the import feature is that it patches your data. Say you export everything to XML, then delete a few comments, make changes to some posts, etc. When you import the XML file, Pegasus checks for already existing objects in the database. If something is not found, it will insert it in the database. Otherwise, it scans the entities and updates missing information. For example, if you have a blog post with 10 comments and you delete 3 of them, when you import the data, the blog post and its related information won't be touched (the post entity, categories and tags, etc.) but the missing 3 comments will be restored.

I needed the import/export functionality because it's always best to be able to export the data via the app itself. Without this, I would have needed to backup the database manually, or generate SQL scripts, etc. This way, I can easily export/import whenever needed without having to access the hosting server. Plus, having the raw data in XML format means I can do more with it. Let's say I wanted to write a desktop client to read the data, or perhaps I want to transform the data and extract some information, you get the gist.

Settings

All application and external settings live in the appsettings.json file. This includes the application settings, search engine verification codes, reCAPTCHA keys, etc.

Account settings

You can change your password, enable two-factor authentication, or recover your account in case you forget your password.

App settings

You can configure the application behavior and static values used across the site:

  • Site name & version
  • Author information (name, email, social profiles)
  • Blog information (title, description, posts per page, etc.)
  • Feed information (used by RSS feeds)
  • SMTP settings (used for outgoing emails)

Search Engines

You can configure multiple search engines by providing their verification codes. The appropriate meta tags will be injected in the main layout. Google and Bing verification codes are required to ensure you cover 98% of the market share by default.

Security

Pegasus uses JWT and Cookies for authentication, and role-based authorization for securing API endpoints.
Proper CSPs (Content Security Policy) and response headers are applied to all requests, ensuring maximum security.

SEO

Pegasus implements a rock-solid foundation for injecting SEO metadata and structured JSON-LD scripts on every page.
You get well structured, schema compliant metadata for search engines, crawlers and social bots alike.

Content Security Policy

Pegasus implements a CSP builder and a security headers middleware. Different policies are applied to different parts of the app which gives you granular control and a maintainable and easy-to-customize foundation.

Health Checks

Health checks are configured and accessible via a secured UI to enable seamless monitoring of the web app and resources in use.

Tech Stack

Programming languageC#
Platform.NET 9
Web FrameworkASP.NET Core
Data AccessEntity Framework Core
Database EngineSQL Server
CSS FrameworkBootstrap 5.3.8
Front-end FrameworkAngular 20.3.7
Background ProcessingHangfire

Pegasus uses many open source libraries, including but not limited to:

Where can I get it?

Although Pegasus is production ready and stable, it's still in active development. I'm planning to open source the project on GitHub. I am going to publish the source code under MIT. Looking forward to see how it's going to be received by the community and if anyone's going to use it on the web. I think .NET developers are going to love it, and who knows, maybe I'll develop Pegasus further into a full blown blog engine in the future.

Background

A few years ago I built a web app for myself using ASP.NET MVC on .NET Framework 4.5. I wanted to have a have a website and tech blog about my work, but I didn't want to use ready-made software. There are numerous open source and free products available, from WordPress and Orchard, to static site generators like Ghost, and Hugo. I wanted to build everything myself to learn more and master my craft. It served me very well as it turned out to be an invaluable opportunity for growth. Over the past few years, this project served as my pet project to try new things and develop my skills further as a software engineer.

Since the first release, I didn't get to blog as much as I liked to. I've been swamped with work. Around mid 2020s I updated the project and cleaned up the code to get ready for serious blogging. But the project was outdated and I was in the middle in of upgrading to .NET Core and Angular 2+. So I thought this is a great opportunity to rewrite the project from scratch and migrate to new technologies.

Around March 2020, I started rewriting Pegasus and at the time .NET Core 3.0 was available, which was great. At first, I wanted to move away from ASP.NET MVC and built a RESTful API with an Angular SPA. The development experience is great when you're working in that setting. Great performance, easy to maintain, TypeScript and Angular components, it's a delight. But soon I realized it won't scale well because SPAs aren't easily SEO-friendly. Of course there are ways to help you rectify, server-side rendering and static site generators, etc. But all that turned out to be overkill and required a lot more work that necessary.

So, I took a break and refactored the solution. I didn't want to lose the Angular SPA and my RESTful API. What I wanted to achieve was, a well structured and performant web application that serves server-side rendered views, with an Angular SPA for the admin dashboard. It took me a few months to put everything together, but it was well worth the effort. I'm very pleased with the end result and everything works great. There's always room for improvement, obviously, and I try to actively maintain the project.