If you’re a .NET or C# developer, the Jamstack approach to building websites might have fallen off your radar over the years. With the development of the Jamstack ecosystem, now might be the right time for you to build on a Jamstack architecture and utilize all your well-deserved .NET skills.
Jamstack—one of the key concepts is pre-rendering. In Jamstack sites, the entire frontend is prepared at the build time, and the resulting static output is served from a content delivery network (CDN).
As a Jamstack developer, you don’t want to write all the logic for transforming your project into static files. Instead, you want to use some tools for this pre-rendering. These tools are doing a lot of fancy stuff for you—usually they allow you to apply templates, handle all the bundling and minification, and provide you with a rich ecosystem of plugins for specific use cases like data fetching from CMS, site map generating, or optimizing images. These tools are called static site generators. But let’s talk .NET now, where a generator called Statiq is quickly becoming a popular option.
Glad you asked! These are not static sites full of GIFs and WordArt from the `90s—though I love those retro feeling ones like on my university programming teacher’s site. Browsers, JavaScript, and APIs have all advanced in capabilities since then. These days you can implement dynamic functionalities like authentication, payments, or search even on static sites
With Statiq! Statiq is a static site generator for .NET. It brings the first-class experience of both Visual Studio and VS Code – including Intellisense and debugging – to the Jamstack world. In combination with the .NET platform and many built-in features like pipelines, modules, preview server, and shortcodes, it is a great entry ticket for .NET developers and teams into Jamstack.
The Statiq project contains a general-purpose static generation framework called Statiq Framework and a convention-based static site generator called Statiq Web that’s built on top of it. From now on, we will be referring to Statiq.Web when talking about Statiq.
For a start, let’s explain some key concepts and specifics of Statiq. I believe these are essential to having a solid base when starting with this static site generator.
A document is a primary unit of information in Statiq. It consists of content and metadata. Imagine that Statiq is like a document database that can process these documents. To be more precise, these documents are immutable. When a document is processed, it’s returned a new instance of the document. Documents are manipulated by modules.
A module is a component that performs a specific action with documents. A module takes documents as input, does an operation based on those documents (possibly transforming them), and outputs documents as a result of whatever operation was performed. Modules are typically chained in a sequence called a pipeline.
A pipeline is a document processing unit. A pipeline consists of one or more modules. Basically, the pipeline is a workflow blueprint of how your modules should handle documents. One might find a slight analogy with a controller in .NET MVC, nevertheless, it’s good to think about pipelines in a more declarative way. You just specify what your output should be rather than how to transform and produce it.
Pipelines have their own lifecycle process defined by phases. When pipelines and modules are executed, the current state is passed in the execution context.
In this section, we’ll create a new static site powered by Statiq from scratch. The site will contain one root page, a listing of the articles, and article detail pages. The example will showcase rendering using Razor pages as well as Handlebars templates. Then we’ll use a third party module for fetching and rendering content from the headless CMS Kontent. In the end, we’ll publish our site to Netlify, with preview functionality.
Note: If you just want to see working code published on Netlify, you can fork my repository and start from Step 7.
Installing the .NET Core SDK is the only prerequisite. This tutorial assumes you are familiar with the basics of frontmatter, markdown formatting, and the .NET ecosystem.
dotnet new console --name StatiqTutorial
from the command line.StatiqTutorial
directory and run dotnet add package Statiq.Web --version 1.0.0-beta.14
(you can find the latest version of the framework on Nuget).Program.cs
.using Statiq.App;
using Statiq.Web;
namespace StatiqTutorial
{
public class Program
{
public static async Task<int> Main(string[] args) =>
await Bootstrapper
.Factory
.CreateWeb(args)
.RunAsync();
}
}
input
folder with an index.md
file with the following content. The input directory is a default path where Statiq looks for input files.---
Title: My First Statiq page
---
# Hello World!
Hello from my first Statiq page.
dotnet run -- preview
Statiq will generate the output
content (same as in the previous step). In addition, it’ll start your server and will serve content from the output directory.http://localhost:5080
.All the magic happened in the CreateWeb(args)
method that created a bootstrapper with Statiq functionality. Default configuration runs your app with several modules. The most important one is default processing of your input markdown files and generating a page with the same name with content in HTML.
Program.cs
and replace it with the code below. With this bootstrapper setup, you tell Statiq you don’t want all the default magic, and you’d rather take care of the content rendering on your own. However, the AddHostingCommands()
is still providing you with preview functionality.using System.Threading.Tasks;
using Statiq.App;
using Statiq.Web;
namespace StatiqTutorial
{
public class Program
{
public static async Task<int> Main(string[] args) =>
await Bootstrapper
.Factory
.CreateDefault(args)
.AddHostingCommands()
.RunAsync();
}
}
input
folder remove index.md
and create a content
directory. In this directory, we’ll have our input files for content. In the input/content
create a new home.md
file with the following code.---
Title: Hello World from Statiq!
Content: This is a root page of the statically generated site powered by Statiq. This page is rendered by Razor view template. Statiq Web is a powerful static website generation toolkit suitable for most use cases. It's built on top of Statiq Framework, so you can always extend or customize it beyond those base capabilities as well. This is an example of how to render one single page.
---
This will be your local content data source file for your home page. It’s a basic frontmatter markdown content with the Title
and Content
properties.
input
directory create Home.cshtml
file with content.HomeViewModel.cs
.Home.cshtml
you’ll find out that your HomeViewModel is not visible from this view. To fix it, create new _ViewImports.cshtml
in the input directory.HomePipeline.cs
file. In the Input phase, this pipeline reads our content/home.md
file. The Process phase uses ExtractFrontMatter
and ParseYaml
modules that get content from this file. We need to somehow connect our input document with our view. We achieve this by using the MergeContent
module in the RenderRazor
module, where we specify how to create an appropriate view model. The SetDestination
module determines where your files will be written. In the last Output phase, we use the WriteFiles
module for writing our output files.dotnet run -- preview
. You should see your markdown content rendered on the Razor page similar to this deployed on Netlify.input/content/features
copy the following markdown files. These will be our content data source for the listing page. You can find content and structure for these files on GitHub.input
folder create FeaturesListing.cshtml
.Feature.cs
, FeaturesListingViewModel.cs
, and FeaturesListingRazorPipeline.cs
. It’s worth mentioning that in the Process phase we are using the execution context of the current pipeline, where we are adding content from our markdown files as children of the document. In the Output phase, we are iterating through the document’s children, and we are creating List<Feature>
features object, which is used by FeaturesListingViewModel
. Other principles are similar to those described in Step 2.dotnet run -- preview
you should see your features listing at http://localhost:5080/features-razor
. 5.If you’d like to use the HandleBars template instead, you can find the pipeline and template on GitHub. The principles are the same.FeatureDetailPipeline.cs
. In the Process phase, this pipeline uses the RenderMarkdown
module that renders markdown.dotnet run -- preview
. Now your links from both (Razor and HandleBars) listing pages leading to the detail one should work.When you want to enable content authors to create and manage content, it’s more convenient to provide them with the capabilities of Headless CMS than to edit your codebase directly. In this step, we’ll create a project in headless CMS Kontent. Moreover, we’ll create a new home page, which will use content from this CMS.
First, we’ll generate strongly typed classes for our content types. This helps us to work with content from the headless CMS in a safe, strongly typed way. Then we’ll use the Kontent.Statiq module to fetch and use our content in the new pipeline.
GenerateModels.ps1
.appsettings.json
. Replace projectId with the one from the previous step.HomeFromCmsPipeline.cs
file. This pipeline uses the Kontent.Statiq module in the Input phase. In the Process phase, we are reusing the Home.cshtml
razor view. All the magic happens in the Process phase. We are creating HomeViewModel
using an already created new constructor. The parameter of the constructor is Statiq’s document created with content from the headless CMS.dotnet run -- preview
. At http://localhost:5080/index-from-cms
you should see your rendered content from the headless CMS.Pro tip: You can also check how your site looks and behaves with unpublished content. Just enable preview mode in appsettings.json
and use the Preview API key from the previous step.
{
"DeliveryOptions": {
"ProjectId": "YOUR_PROJECT_ID",
"PreviewApiKey": "YOUR_API_KEY",
"UsePreviewApi": true
}
}
We will create two sites on Netlify. While one will build our production site with published content, the other one will use unpublished preview content. Netlify’s built machines got installed .NET5 framework by default. Make sure in your project’s .csproj
file you are targeting net5.0
as a target framework.
appsettings.json
. We will provide these settings in the form of environment variables. If you don’t want to follow all the previous steps, you can fork my repository and start from here.dotnet run
as a Build command and output
as a Publish directory. Add a new DeliveryOptions__ProjectId
variable and enter your projectId. Note: Netlify uses double underscore (__) as the delimiter for the nested environment variables.DeliveryOptions__ProjectId
add two new environment variables DeliveryOptions__PreviewApiKey
with your Preview API Key value and DeliveryOptions__UsePreviewApi
with true value.Pro tip: Add webhooks for rebuilding your site when content is changed. You can learn more about Kontent webhooks and Netlify build in this article.
This tutorial is meant to be an introduction to the Statiq static site generator. There are opportunities for you to make additions to the code around styling, SEO, and even adding JavaScript for more capabilities. If you would like to use a more complete template, I’d recommend the Statiq Lumen starter, which is a blog site built with Statiq and Kentico Kontent that uses SEO best practices and had a great Lighthouse score. Another resource on connecting Statiq with the CMS is Jamstack on .NET: From zero to hero with Statiq and Kontent.
Originally published at netlify.com.