Building a flat website with ASP.NET Core
Tags: showdev, devdiary, ci, aspnetcore
Published: 2019-02-22 01:52:49

---
title: Building a flat website with ASP.NET Core
published: true
description: My setup for a few of my websites
tags: showdev, devdiary, ci, aspnetcore
---

As of last night, I [launched the website for BrandVantage](https://brandvantage.co), my product I am building. I'm pretty proud of the site, I designed and built it myself as well as designed the logo. This all happened in just over one week since [I left my job](https://dev.to/turnerj/i-left-my-job-today-f1a) too!

I touched on a little what BrandVantage was about [in a comment](https://dev.to/turnerj/comment/8mlf) but this, and various other posts coming soon, are to talk about development and technologies, not me trying to sell you on it. When I do launch on Product Hunt, I will probably post about that though! 🙂

This new site, as well as [my personal site](https://turnerj.com/) and [my company's website](https://www.turnersoftware.com.au/) (both also launched not too long ago) are all built very similarly: a single-page, flat HTML with minified CSS.

I like having a flat site like this as it is hosting agnostic. These sites I have built, while are ASP.NET Core projects in code, they are deployed to PHP hosting. The rest of this post explains that setup a little.

## The Base Project
I'm using Visual Studio with each of these projects starting out the same, an empty ASP.NET Core website project.

![Visual Studio Solution Structure](https://thepracticaldev.s3.amazonaws.com/i/ucj71u7t59rzo59ui7tk.jpg)

For getting the actual project working in development, you will need to update your `Startup.cs` to be something similar to below:

```csharp
public class Startup
{
	public void Configure(IApplicationBuilder app, IHostingEnvironment env)
	{
		if (env.IsDevelopment())
		{
			app.UseDeveloperExceptionPage();
			app.UseBrowserLink();
		}

		app.UseDefaultFiles(new DefaultFilesOptions
		{
			DefaultFileNames = new List<string> { "index.html" }
		});

		app.UseStaticFiles();
	}
}
```

You want to make sure you have `UseStaticFiles` and set your index file to be a default otherwise it won't work as you expect.

## Site Root
![Site Root](https://thepracticaldev.s3.amazonaws.com/i/5iclmdc6knt6e0tdv9mc.jpg)
This setup really is taking it back to basics, I'm not using any special features of ASP.NET Core itself, there isn't some Razor template I am exporting to flat HTML. It really is just one `index.html` file that I've manually built.

I did look into trying to export a site from CSHTML into plain HTML but it seemed a little too complicated for a single page site. I might revisit this in the future but for now, a flat HTML page is perfect for me.

## Bundling and Minification

My setup relies on the Nuget package [BuildBundlerMinifier](https://www.nuget.org/packages/BuildBundlerMinifier) which allow the minification of CSS by just simply building the codebase as you would any other .NET codebase.

It uses a JSON file which for me looks like:
```json
[
  {
    "outputFileName": "wwwroot/bundles/site.min.css",
    "inputFiles": [
      "wwwroot/css/normalize.css",
      "wwwroot/css/layout.css",
      "wwwroot/css/product-hunt.css",
      "wwwroot/css/responsive.css",
      "wwwroot/css/compatibility.css"
    ],
    "sourceMap": true
  },
  {
    "outputFileName": "wwwroot/fonts/font-awesome/bundles/fontawesome.min.css",
    "inputFiles": [
      "wwwroot/fonts/font-awesome/css/fontawesome.min.css",
      "wwwroot/fonts/font-awesome/css/light.min.css"
    ]
  }
]
```

The bundler/minifier does support JavaScript but I don't have any JS in my site besides Google Analytics and a Product Hunt script.

You can see in my site root screenshot that there is a `bundles` folder, that is created by this process however I have that excluded from Git.

Because my site is flat HTML, I do need to reference the bundled files directly which I do as shown here:
```html
	<link href="/bundles/site.min.css" rel="stylesheet" />
</head>
<body>
	<link href="fonts/font-awesome/bundles/fontawesome.min.css" rel="stylesheet" />
```
> The reason for one being in the `head` and one being in the `body` is slightly increasing the perception of a faster page load.

One downside to this entire flat HTML method is that these bundled files aren't regenerated on the fly. This means I need to build again every time I want to view a CSS change. For major works, I might manually revert back to non-minified CSS just to make development easier. Ideally though, you would have it auto-generate on modification - this is something that many other tools provide but I don't (yet) have in my setup.

If I were to use CSHTML, I could actually reference both and use tag helpers to define what environment I am running in. Again, something I might consider for the future.

## Continuous Delivery
You might have noticed in that first screenshot there is a cheeky `build-pipeline.yml` file, this is used by Azure DevOps Pipelines to allow me to automate my build and deployment setup.

My file looks like this:
```yml
resources:
- repo: self
queue:
  name: Hosted VS2017

steps:
- task: DotNetCoreInstaller@0
  inputs:
    version: '2.2.101'

- task: DotNetCoreCLI@2
  displayName: 'dotnet build'

- task: ArchiveFiles@2
  displayName: 'Archive src/Website/wwwroot'
  inputs:
    rootFolderOrFile: src/Website/wwwroot
    includeRootFolder: false
    archiveType: 7z
    archiveFile: '$(Build.ArtifactStagingDirectory)/website.7z'

- task: PublishBuildArtifacts@1
  displayName: 'Publish Artifact: Web'
  inputs:
    ArtifactName: Web
```

I'm no expert on Azure DevOps Pipelines but the above is what I have working for me. First it installs a specific version of .NET Core, just so I have a stable and consistent environment (as .NET Core is already installed). I then run a build which really is just running the minification process. The next two tasks are required for getting the data to package up the build for the deployment pipeline.

At the time of making this setup, Azure didn't support a full YML config for the deployment side of the pipeline so I can't show that to you. The short version of what it does is:
- Waits for a new build package coming from the master branch (allowing me to use other branches for dev without fear of deploying them)
- Unpacks the artifact
- Using FTPS, deploys all the changes to my hosting

## Conclusion
Maybe not the greatest or most productive setup but one that works pretty well for me. What I can strongly say though is how much I love automated deployments - that stuff is amazing!