Four years ago I wanted to create a professional blog and I was searching for a simple solution without those monolithic features of wordpress. That's how I found Grav and started to use it. I like to write in markdown and liked the concept of database-less design. Unfortunately I didn't have the time to keep on writing so it lived only for four posts that you can now read here.
Years later I discovered Github pages and Gitlab pages, these handy static web serving solutions along with the correspondent static site generators like Jekyll and Hexo and decided that some day I will reboot my blog with one of these tools.
Then I was thinking if there is a product for the job that is created in dotnet core, but I didn't find any, so I decided to write my own! That's how Bloggen.Net was born.
The goal was to learn by experimenting, so I didn't want to copy an existing software, I wanted it to evolve with my blogging needs, and they are quite minimal:
So I created a blank console app project and split the responsibilities in modules with well defined interfaces. The modules are wired together through the default dotnet core DI container.
There are two types of configuration:
config.yml
that is parsed by default dotnet configuration provider, extended by Yaml configuration parser packageThe YAML provider is dependent on YamlDotNet that is also used by the software.
This module defines an interface through which the software can get all the required sources (index template, layout templates, partials, posts, pages). The concrete implementation is a FileSystemSourceHandler that reads the sources from the filesystem.
This module is responsible for the deserialization of front matter headers in posts and pages with their metadata. Uses YamlDotNet.
This module represents the data model and relations between blog objects' metadata. Currently there are three types:
IPost
: represents a blog post metadataIPage
: represents a page metadataITag
: represents a tag metadataThe main interface is IContext
(inspired by EF core) that holds the collections of these three types with references to each other. The implementation Context
collects all the metadata through serialization and cross-references these objects.
This module parses the markdown from the source post and page files and renders them to html strings. The concrete implementation uses MarkDig.
This module renders templates to the given TextWriter
.
You can hardly find a good templating library in the dotnet core ecosystem if you can't use Razor. Razor is tightly coupled to aspnet core and it's a bit hacky to use it in a console application. I had another project where I generate my rock band's static homepage based on social media API-s, and I used Handlebars.Net, a handlebars.js port there. It worked well so I kept it.
This module puts the whole thing together. It has only a Generate()
public method and does the work internally. It also holds the concrete implementations of the model interfaces defined in Model. The underlying implementation is FileSystemOutputHandler that renders all the parts to corresponding html pages in their subfolders.
The generation process is something like this:
And that's it. The blog is ready to be published! For more details about usage see the project readme
Because I'm writing these lines using this "engine", I'm sure it will evolve in the future as new needs occur. There are a lot of features that would be handy, like RSS, archives, etc. Follow this blog and I'll let you know if new features are added!