Generating static sites from ASP.NET Core MVC apps
Related postsASP.NET Core Static websites Static Site Generator Nuget
- Practical Clean Architecture solution template
- Offloading And Scheduling Jobs With Hangfire Microservices
- OAuth PKCE flow for ASP.NET Core with Swagger
- ASP.NET Core integration tests with NUnit and Moq
- Simplifying observability in .NET distributed systems
- Simple and secure custom API Keys using ASP.NET Core
As a long time .NET developer, it has bothered me that there is no way for us to have cheap/free apps using the tools we know. Think of this simple/common scenario:
You are a C#/.NET developer that knows a bit of web development but not a lot (or not at all) of the multiple JS frameworks that exist these days. You want to develop a simple static website for yourself or a friend/family member and you want it to be as cheap as possible, and even better if it's free since it's not a critical website. What are your options?
- Write the entire website with just HTML+CSS+JS. While you know the technologies and you can do it, you have to remember to update all HTML files each time you want to update the header/footer.
- Spend countless hours learning a new JS framework (React.js, Vue.js, Angular, etc. etc. etc.). This gives you a lot of flexibility and you can end up with a great site, but do you have the time to learn the framework, and is the site dynamic enough to warrant the download time of all the libraries?
Let's go through another scenario. You are developing a website for a product/service that may need a back-end in the future if things go well. You don't want to pay for a backend now since you don't need it, but then you have again the same problem. Either you:
- Do it all in some static/client-side framework, and spend the time learning the framework and whatnot. Then, when the need arises, you recreate the application in ASP.NET Core MVC as you would have done normally. Or,
- You pay for the hosting of ASP.NET Core from the beginning.
What is clear is that we are missing a way to use ASP.NET Core MVC without paying for a back-end when it's not necessary. Unfortunately, Microsoft has never given us something similar to this. While we have options like Blazor, that is again a new framework to be learned, and you need to keep in mind the limits around WebAssembly, not to mention the huge size of the libraries for just a static website.
Introducing the .NET tool: ssg
I recently started thinking about the idea of compiling all Views from an ASP.NET Core MVC into HTML files that can then be used as a static website. Since Razor supports view compilation through services, this could also be used to generate HTML files.
From this idea and toying around with the framework, the
ssg .NET tool was born: https://github.com/CamiloTerevinto/TerevintoSoftware.StaticSiteGenerator.
How it works
This .NET tool works as follows:
You create your ASP.NET Core MVC projects as usual. You use Controllers, Views, Layouts, Partials, and so on, and use Visual Studio (or VS Code) to run your app locally.
When you are happy with the application as it is, you install the .NET tool (if not previously installed). This can be done globally, for example, as follows:
dotnet tool install --global TerevintoSoftware.StaticSiteGenerator.Tool
The tool can then be invoked with the following command (release 1.x):
ssg --project path --output path
--projectrefers to the directory of the MVC project. It is expected that the Views folder contains the project's Views, and the wwwroot folder contains the static assets that the web app uses.
--outputrefers to where the tool will store the generated files.
The ssg tool then:
- Copies all the files from the wwwroot folder into the output folder, removing the wwwroot since that is not part of the route of the compiled files.
- Loads the assembly given, finds the views and generates an HTML file for each non-partial view it finds. For example:
Home/Index.cshtml=> rendered as
Home/About.cshtml=> rendered as
Blog/Index.cshtml=> rendered as
This results in the output folder containing all the necessary files ready to be published into a hosting provider. For example:
If we look at the index file, for example:
<head> <title>Home Page - Static Site Generator Demo</title> <link rel="stylesheet" href="/lib/bootstrap/dist/css/bootstrap.min.css"> <link rel="stylesheet" href="/css/site.css"> </head> <body> <header> <nav class="navbar"> <div class="container-fluid"> <a class="navbar-brand" href="/index.html">Demo</a> <div class="navbar-collapse"> <ul class="navbar-nav flex-grow-1"> <li class="nav-item"> <a class="nav-link text-dark" href="/index.html">Home</a> </li> <li class="nav-item"> <a class="nav-link text-dark" href="/blog/index.html">Blog</a> </li> </ul> </div> </div> </nav> </header> </body>
You can see that this is a standard MVC template layout (with a few minor changes), that rendered the body, which is also from the MVC template.
If we look at the transformation as a whole:
The good part of this being a .NET tool that can be run after the website is compiled, is that it also allows for more complex setups. For example, you could have a GitHub pipeline that builds the application, installs the tool, renders the site into HTML, and publishes the output into a hosting site (like Google's Firebase, Azure's Storage Account Static Website, Azure's Static Web Apps, AWS' S3, and so on).
If you read this far and want to help build this, please know your contributions are welcome in the GitHub repository: