Jamstack on .NET: From zero to hero with Statiq and Kontent
Ondřej Chrastina
Posted on November 30, 2020
Are you interested in Jamstack, but sad you can't practice it with .NET? The times have changed, and .NET developers are now able to build Jamstack apps using the new static site generator Statiq. This article walks you through the setup of a ready-to-use boilerplate! If you are new to Jamstack on .NET, follow the steps below to wrap your head around the basics. If you know the drill, skip that part and use the boilerplate.
By default, the content is loaded from a shared Kontent.ai project. If you want to use your own clone of the project so that you can customize it and experiment with Kontent, continue to the next section.
Create a content source
Application itself is configured to use shared alvawys avalable Kontent-ai project.
If you want to generate the clone of the project in order to be able to edit the content, use Sample site generator.
Use "CREATE A NEW SAMPLE PROJECT" for generating the project.
Let's briefly introduce Jamstack. It is a web architecture based on the pre-rendered assets (HTML files, images, CSS, etc.) that are generated at the build time based on templates and data.
Now, let's jump right to the available technologies. First is Statiq, a generation platform providing the .NET based Statiq.Framework for creating a static site generator infrastructure and a set of modules called Statiq.Web that will make the initial configuration of the framework easier.
The next pieces of the puzzle are the templates and data storage. I have chosen Razor as a template engine since it is the most known one in the .NET world. Data will be provided by a headless CMS—Kentico Kontent. It provides more flexibility and collaboration features in comparison with markdown files, and it has a Statiq module out of the box.
The whole boilerplate creation is split into three parts—an application skeleton, a content source, and a connector that allows Statiq to generate pages.
💡 At this point, if you rundotnet run -- preview, you can browse your empty site athttp://localhost:5080 💡
Prepare content
As the title mentioned, the boilerplate is about going "from zero to hero". This means creating a "Hero" content model that consists of a headline, summary, and CTA. Plus creating one content item based on that model. We'll do all that in a headless CMS Kentico Kontent as it already features Statiq integration.
The link above will provide you with a 90-day trial. Once you finish the trial, or even during the trial period, you can switch to theDeveloper plan, which isfree of chargeand lets you run small projects with a $0 budget.
After generation, you will end up with three files Models/Hero.Generated.cs, which is a POCO model class, then Models/Hero.cs that allows extending the model class, and the last one is Models/CustomTypeProviders.cs that will be used to provide model mapping information.
The next step is to initialize the Kontent Delivery SDK client for dependency injection. Extend Program.cs file with ConfigureServices.
usingSystem.Threading.Tasks;usingFromZeroToHero.Models;usingKentico.Kontent.Delivery.Abstractions;usingKentico.Kontent.Delivery.Extensions;usingMicrosoft.Extensions.DependencyInjection;usingStatiq.App;usingStatiq.Common;usingStatiq.Web;namespaceFromZeroToHero{publicclassProgram{publicstaticasyncTask<int>Main(string[]args)=>awaitBootstrapper.Factory.CreateWeb(args).ConfigureServices((services,config)=>{// Add the type providerservices.AddSingleton<ITypeProvider,CustomTypeProvider>();// Configure Delivery SDKservices.AddDeliveryClient(opts=>opts.WithProjectId("<projectid>").UseProductionApi().Build());}).RunAsync();}}
All of your assets and templates should be placed in the /input folder. Create a view file _Hero.cshtml in the /input folder then and use the generated FromZeroToHero.Models.Hero class as a model for the template.
And finally, to connect the configured client to load the data to the model and pass them to the Razor engine, we will define a new Statiq Pipeline. The pipeline is like a Controller from MVC. Create a new file in Pipelines/HeroPipeline.cs. By inheriting from Statiq.Core.Pipeline, Statiq automatically includes your pipeline in the generation process.
usingFromZeroToHero.Models;usingKentico.Kontent.Delivery.Abstractions;usingKentico.Kontent.Delivery.Urls.QueryParameters;usingKentico.Kontent.Delivery.Urls.QueryParameters.Filters;usingKontent.Statiq;usingStatiq.Common;usingStatiq.Core;usingStatiq.Razor;namespaceFromZeroToHero{// <see href="https://statiq.dev/framework/pipelines">Pipelines documentation</see>publicclassHeroPipeline:Pipeline{publicHeroPipeline(IDeliveryClientclient){ProcessModules=newModuleList{// Load the "Hero" item and transfer it into IDocument.// <see href="https://github.com/alanta/Kontent.Statiq">Kontent.Statiq</see>newKontent<Hero>(client).WithQuery(newEqualsFilter("system.codename","hero"),newLimitParameter(1)),// Load Razor template to IDocument content.// <see href="https://github.com/statiqdev/Statiq.Framework/blob/main/src/core/Statiq.Core/Modules/Content/MergeContent.cs">MergeContent</see>.// <see href="https://statiq.dev/web/content-and-data/content/">Content propery of IDocument</see>newMergeContent(newReadFiles(patterns:"_Hero.cshtml")),// Render HTML file from Razor template and document typed as Hero model.// <see href="https://github.com/statiqdev/Statiq.Framework/blob/main/src/extensions/Statiq.Razor/RenderRazor.cs">RenderRazor</see>newRenderRazor().WithModel(KontentConfig.As<Hero>()),// Set file system destionation for the document.// <see href="https://github.com/statiqdev/Statiq.Framework/blob/main/src/core/Statiq.Core/Modules/IO/SetDestination.cs">SetDestination</see>newSetDestination(newNormalizedPath("index.html")),// Flush the the output.// <see href="https://github.com/statiqdev/Statiq.Framework/blob/main/src/core/Statiq.Core/Modules/IO/WriteFiles.cs">WriteFiles</see>.newWriteFiles()};}}}
🚀 Done! Now rundotnet build -- previewand see your first hero page athttp://localhost:5080🚀
The following sections describe how to extend a boilerplate with Razor layout standards, basic styling, and configuration settings. These changes are already included in the boilerplate.
Razor conventions
Razor works the standard way in the Statiq environment. By creating _Layout.cshtml in the input folder and specifying the default layout in _ViewStart.cshtml like below, you prepare the standard setup for adding the pages with the same layout (as was done in this commit with _Hero.cshtml template).
@{
Layout = "_Layout";
}
Sass
Since the Sass (as well as Less) is already pre-configured in Statiq.Web default modules, it is possible to create a sass file in the input folder and then reference it by the same name with .css extension. Create main.scss file and reference its transpiled version in the Razor view using @IExecutionContext.Current.GetLink("/main.css") and add some basic styling (see the implementation).
Extract Project ID
It is a good idea and a .NET best practice to extract configuration to settings files. To extract the Kontent delivery client configuration to this file, create an appsettings.json file with the DeliveryOptions section containing only one property ProjectId. Then in Project.cs configure the delivery client to dependency injection (see the implementation):
That action also opens the door for you to use different sets of configurations depending on the environment i.e. use configuration with a preview API key for your local development environment.
Conclusion
In this article, I showed you how to build a simple Jamstack site using .NET and static site generator Statiq. We created a new content type with some content in a headless CMS, connected the CMS to our application, and converted the data into generated static pages. Find the complete implementation here:
By default, the content is loaded from a shared Kontent.ai project. If you want to use your own clone of the project so that you can customize it and experiment with Kontent, continue to the next section.
Create a content source
Application itself is configured to use shared alvawys avalable Kontent-ai project.
If you want to generate the clone of the project in order to be able to edit the content, use Sample site generator.
Use "CREATE A NEW SAMPLE PROJECT" for generating the project.