Pegasus

A blog engine for ASP.NET Core

jarallax-cover

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

Features

Here's an overview of the core features, some features have more detailed explanation.

Categories

Pegasus supports hierarchical categories, and posts can be filed under multiple categories. Categories are unique, meaning you can't have multiple categories with the same title or slug. A root category is seeded in the database and posts that don't have any categories, will be filed under the root category. The root category is named Miscellaneous by default, but it can be renamed.

Tags

You can define as many tags as you like, and posts can have multiple tags. Like categories, tags are unique too.

Posts

Blog posts are written in HTML, using the TinyMCE editor. Each post has a title, an excerpt, and the body content. All of which are required fields. You can configure the following settings for each post:

Publish 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 the slug will be generated based on the title, or you can enter whatever value you like.

Metadata

The keywords and description values are used for SEO meta tags.

  • Comma separated keywords
  • Description

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

You can upload a cover image for your posts, or you can leave it alone and use the Pexels Service (described in the Settings section).

Discussion

  • Allow comments (if turned off, comments and replies won't be accepted)
  • Allow Trackbacks (not implemented, could be used for Pingbacks and Trackbacks)

Comments

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 the TinyMCE editor, but only support a subset of editing features. You can leave root-level comments, or reply to previous comments. Google ReCAPTCHA is used for handling spam requests. By default, comments need moderation before they are published. In the dashboard, you can view newly posted comments. As the administrator, you can edit comments, approve or decline, or delete them from the database.

Feeds

The blog feed is available in RSS and Atom formats. 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 to be used by search engines, but could be used for other needs as well.

Import/Export

You can export the data to an XML file, or a Zip archive. The zip archive includes the XML file, plus the media folder (image uploads used in posts). 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, Pegasus will insert it in the database. Otherwise, it scans the entities and updated any 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, etc.

Currently, the import/export feature works with Pegasus only. But it could be developed further to support other formats. For instance, I could develop the app to support WordPress and Google Blogger too.

Settings

You can manage application settings in the dashboard.

Account settings

Here you can change your password, enable two-factor authentication, etc.

App settings

Here you can change the application behavior and values used across the UI:

  • App Name (website name)
  • App Version
  • Author Name
  • Author Bio
  • Author Email
  • Blog Title
  • Blog Description
  • Posts per page
  • Feed entries count (posts per RSS feed)
  • Feed Title
  • Feed Description
  • Social Media Profiles
    • Facebook handle
    • Twitter handle
    • Github handle
    • Linkedin handle

SMTP settings

Here you can change the SMTP settings used for outgoing emails.

  • Host
  • Port
  • Enable SSL
  • Username
  • Password
  • From Address

Pexels settings

Pegasus integrates with Pexels API for getting random cover images. You can toggle two useful features on and off:

  • Pexels Service - if enabled, posts that don't have a local cover image, will try and fetch a random image from the Pexels API.
  • Pexels Cache - overrides the Pexels Service feature. If enabled, the application populates a cache entry with a list of Pexels images. Subsequent calls to load blog posts, will load cover images from the cache (if they don't have a local cover image).

Pegasus also supports a fallback mechanism for cover images. If a blog post doesn't have a cover image, and if the Pexels services are disabled (or threw errors for whatever reason), the app loads a local image from the file system. This is by design, and the idea is that all posts should have a cover image for a consistent look and feel.

Tech Stack

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

Pegasus uses numerous 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 and .NET 4.5. I wanted to have a have a website and 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, etc. 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 on and develop my skills further as a software developer.

I didn't get to blog and populate my website with good content - unfortunately - because I've been swamped with work and life. Last year, in 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 time to rewrite the project from scratch and migrate to new technologies.

A year ago (March 2020) I started rewriting the project 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 code, TypeScript and Angular components, it's a delight. But soon I realized it won't scale well because SPAs aren't SEO-friendly. Of course there are tools to help you rectify, server-side rendering and static site generators. But that's overkill, and requires a lot more work. And in the end it still wouldn't be a good solution.

And so I took a break and refactored the solution, but 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, because I'm working full time as a lead developer, but it was worth the effort. I'm very pleased with the result and everything works great, there's always room for improvement too, obviously.