Cloud Concept Limited Logo

Static site generation in a dotnet 8 webapp

astro
Neil Tomlinson
#astro#dotnet

Static site generation in a dotnet 8 webapp

Introduction

There are many reasons why we would like to load pages quickly for instance a customer visiting a product page might get tired of waiting and head somewhere else resulting in a lost sale. If we are doing lots of back end processing to personalise a page then what the customer experiences is a delay in the page loading times.

On the server side we might try to handle this with caching in .NET. We can use response caching and output caching plus we can add a layer of in-memory caching. Unfortunately we still need to load the cache usually meaning that some visitors are punished with slow page loads. This also adds complexity to the code and difficult to debug issues. If there is very little variation between what the visitors see do we need to repeat this processing at all? Can we instead generate these content based pages ahead of time? In this case we of course still have caching, of course, but it is the whole page cached on a disk and we can just serve these up directly from the web servers which is where they excel. Additionally, moving the processing burden to be at compile time means we can benefit by running the application on less powerful hardware.

Usage

Of course using a static site generator depends on your use case. Below are some examples.

Good fit for:

Not such a good fit for:

Why I did this

I picked up astro for building static websites and really enjoyed the experience then I turned my attention to how I might be able to use this in other projects particularly with .NET. I have been a .NET developer for many years but I haven’t found a .NET site generator that I have wanted to use.

What I wanted to emulate is a content driven site where most of the site is static but then there is some back end functionality, for instance we want a product service that can give live stock availability or a service to give a small level of personalisation such as retrieving recommended products. This could be achieved in other ways but I wanted to see how it might look to have this running in one .NET project similar to the dotnet new angular or react templates.

What I did

As mentioned I took what is in the dotnet new angular or dotnet new react as my starting point.

.NET default templates for dotnet new - .NET CLI

These templates are from .net 6 but have not been updated for .net 8 release. the ASP.NET Core 6.0 release also changed how these templates worked.

What’s new in ASP.NET Core 6.0

Improved single-page app (SPA) templates

The ASP.NET Core project templates have been updated for Angular and React to use an improved pattern for single-page apps that is more flexible and more closely aligns with common patterns for modern front-end web development.

Previously, the ASP.NET Core template for Angular and React used specialized middleware during development to launch the development server for the front-end framework and then proxy requests from ASP.NET Core to the development server. The logic for launching the front-end development server was specific to the command-line interface for the corresponding front-end framework. Supporting additional front-end frameworks using this pattern meant adding additional logic to ASP.NET Core.

The updated ASP.NET Core templates for Angular and React in .NET 6 flips this arrangement around and take advantage of the built-in proxying support in the development servers of most modern front-end frameworks. When the ASP.NET Core app is launched, the front-end development server is launched just as before, but the development server is configured to proxy requests to the backend ASP.NET Core process. All of the front-end specific configuration to setup proxying is part of the app, not ASP.NET Core. Setting up ASP.NET Core projects to work with other front-end frameworks is now straight-forward: setup the front-end development server for the chosen framework to proxy to the ASP.NET Core backend using the pattern established in the Angular and React templates.

The startup code for the ASP.NET Core app no longer needs any single-page app-specific logic. The logic for starting the front-end development server during development is injecting into the app at runtime by the new Microsoft.AspNetCore.SpaProxy package. Fallback routing is handled using endpoint routing instead of SPA-specific middleware.

Templates that follow this pattern can still be run as a single project in Visual Studio or using dotnet run from the command-line. When the app is published, the front-end code in the ClientApp folder is built and collected as before into the web root of the host ASP.NET Core app and served as static files. Scripts included in the template configure the front-end development server to use HTTPS using the ASP.NET Core development certificate.

dotnet new mvc

In the ClientApp directory I created a simple new astro site using the astro.build documentation here : https://docs.astro.build/en/install/auto/

npm create astro@latest

I used the prestart scripts from the spa projects that set up the ssl certificates that are used by the dotnet app

DotnetAstroPreStartScripts.png

I added sections in the csproj file for moving the compiled static site to the wwwroot folders; these are used when we publish the web app to a web server.

DotnetAstroCsproj.png

We also need to add proxy configuration to delegate api requests to the .NET app when we debug the astro site locally.

DotnetAstroAstroConfig.png

I’ve created a github repository with all the code here https://github.com/nptomlin/dotnet-astro

Thoughts

I’m pretty satisfied with the result and I could probably adapt and use this project as some kind of campaign microsite.

Running this locally is different to how this would run in any other environment. I like my local environment to closely match the server, otherwise you can get issues that can’t be reproduced in all environments or implementation problems that don’t get spotted until the code is deployed to a server.

I wonder if it would be much more simple to use one dev stack all the way through. A couple of examples might be: use astro with server side rendering or perhaps dotnet and blazor.

If I was to do anything more complicated I would approach this differently. I would probably split the projects and use some kind of gateway to route requests to the relevant place.

Other things to look at

Enterprise grade architecture for JavaScript https://github.com/Azure-Samples/contoso-real-estate

Separate front end and back end projects https://github.com/Azure-Samples/todo-csharp-cosmos-sql

Photo by Jeremy Thomas on Unsplash

← Back to Blog