There are not a lot of tool in ASP.NET that allows you to generate static content on a site. The only good one out there is Wyam written by Dave Glick.
Others are excellent but they have the problem of running on NodeJS. While I don’t have a problem with node, lots of other .NET developers do. Most of them don’t write JavaScript for a living and would just like to use the latest tech to get things done.
So I came up with a proof of concept.
What I want to do?
I want to be able to create static files for a website without having to run the ASP.NET MVC pipeline every time. I’m talking here about content that doesn’t change very much.
From there, we’ll ensure that ASP.NET Core can serve those static files without having to resort to running MVC.
Can it be done? Have I gone mad? The answer is yes.
ASP.NET Core Architecture
The architecture of ASP.NET Core allow us to be at any time, part of the pipeline of the content generation.
One of this piece of this architecture is a Middleware. What’s a middleware? It’s an element of a pipeline that is ran before and after the actual user code. Elements of a pipeline are executed in order and call the next one in the pipeline. This allow us to run pre/post within the same class.
The theory here is, if we are high enough in the pipeline, we can intercept calls after they reach ASP.NET MVC to generate our files but low enough so that Kestrel can still serve our static files.
Startup.cs
First, we need to ensure that we set our Startup.cs properly. The first middleware are going to check for the default files. If they are found, they will stop the pipeline and just serve the file. If they are not found, they will get our middleware and finally MVC.
1 | app.UseDefaultFiles(); // <== this is not present by default. Add it. |
Here’s how it would look like visually.
As the request comes in, each middleware is executed in order and once the bottom of the pipeline is reached, each middleware gets to execute one last time on the way up.
Creating StaticGeneratorMiddleware
1 | public class StaticGeneratorMiddleware |
What does it do?
It will create a folder hierarchy under your wwwroot
folder and create index.html
files that match the request URL.
Once the file exist, other request on the same URL will find the index.html
that was created and skip the whole pipeline.
Pushing it further?
If we want to go mad scientist here, we could create a crawler that would access the urls on our site or maybe even generate a sitemap and loop on those urls.
What would happen is that everything that was served as HTML by MVC would be located in our wwwroot
folder. We could then technically take this folder and just put it on any web server nad it would host your web site.
Pushing it to the cloud
Another step we could take is instead of outputting to disk, we would output to Azure Blob Storage. Immediately, you could spawn any instances of websites and none would access MVC unless the blob storage didn’t already exist.
Revoking files
Another middleware that should be added above UseDefaultFiles
and UseStaticFiles
is a middleware that would delete files after certain conditions. Otherwise, we will never regerate those files.
Creating files in a separate folder
First, you’ll need to update your UseStaticFiles
to look like this:
1 | app.UseStaticFiles(new StaticFileOptions |
Then, you will need to adapt the middleware to generate it in the proper directory.
1 | var destinationFile = Path.Combine(_hostingEnvironment.ContentRootPath, "staticgen", baseUrl, "index.html"); |
Conclusion
With a simple middleware, we can generate static content directly from ASP.NET Core and allow it to be served locally without any other plugins.
Is there easier way to go static with ASP.NET Core? Probably.
Am I still mad? Yep and I stand by my crazy code.