Creating a boilerplate Umbraco 9 site using project templates - part 1
Tags: umbraco, csharp, core
Published: 2021-09-30 18:46:19

With Umbraco 9 freshly releases and running on .NET 5 lots of people need to change the way they work. One of those changes is probably to replace your current boilerplate solutions with a fresh one.

This blogpost will show you how to leverage the built in dotnet templates to do that in a very nice and easy way - let's get started!

## Setting up a basic template based on an Umbraco site

### Set up the site

Before we turn it into a template - is to create the basic site you want to reuse. For the purpose of this tutorial I will use the wonderful demo site made by Dennis Adolfi as a starting point: https://github.com/Adolfi/UmbracoNineDemoSite.git

### Create the template files 

In the root of the repository create a folder called `.template.json`. Inside it create a `template.json` file, with the following basic content:

```csharp
{
    "$schema": "http://json.schemastore.org/template",
    "author": "Jesper Mayntzhusen",
    "classifications": ["Umbraco", "WebApp"],
    "identity": "Testing.Boilerplate",
    "name": "Testing boilerplate solution",
    "shortName": "test-bp",
    "tags": {
        "type": "project",
        "language": "C#"
    },
    "sourceName": "UmbracoNineDemoSite"
}
```

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5tpjvkivqlxq2omgzpvz.png) 

## Testing out the basic template

At this point we have what we need to pack the site up into a dotnet template - of course we will do lots more later. But first let's check that it works!

First of all, let's run a [super helpful PowerShell script](https://github.com/sayedihashimi/template-sample#how-to-test-template-changes-locally) created by Microsoft Program Manager Sayed Ibrahim Hashimi:

```js
function Reset-Templates{
    [cmdletbinding()]
    param(
        [string]$templateEngineUserDir = (join-path -Path $env:USERPROFILE -ChildPath .templateengine)
    )
    process{
        'resetting dotnet new templates. folder: "{0}"' -f $templateEngineUserDir | Write-host
        get-childitem -path $templateEngineUserDir -directory | Select-Object -ExpandProperty FullName | remove-item -recurse
        &dotnet new --debug:reinit
    }
}
```

If you run this in a PowerShell terminal you can then run the function later on to clean up - more on that later.

In the terminal navigate to a folder you want to install your new site based on the template.

Install your new template with a path to your template repository - for me it in a sibling folder:

```
dotnet new --install ..\BoilerPlate\
```

You should see something like this:

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wev1pvuuqwwm1e75bjsv.png)

Note the shorthand for creating the new template is `test-bp` - which is what I set in the `template.json` file in the beginning. 

Now that the template is installed we can use it to create our test site:

```
dotnet new test-bp -o MyTestSite
```
_-o specifies an output folder, and if no name is specified it will use the foldername so don't have to set -n as well_

If you look at the new project it created you will see it is a copy of the one we cloned from Github - except it renamed all instances of `UmbracoNineDemoSite` to `MyTestSite`. This is because that was what we set as the `sourceName` in the template.json file.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l8fldr9fs6siviyn30jr.png)

Pretty easy so far!

## Adding additional parameters

The sourceName parameter is a standard required parameter for dotnet templates - but if your sites are set up like ours you may need to run replacements more than for just 1 name. For that we can add additional custom parameters - these will all be available as command line params or form fields in VS.

There is another special parameter for setting the framework - for that we can add this in the template.json (remember to do this in the boilerplate solution - not the new one you created based on it):

_Add it right at the end below sourceName:_

```json
    "sourceName": "UmbracoNineDemoSite",
    "symbols": {
        "Framework": {
            "type": "parameter",
            "description": "The target framework for the project.",
            "datatype": "choice",
            "choices": [
                {
                    "choice": "netcoreapp3.1",
                    "description": "Target netcoreapp3.1"
                }
            ],
            "replaces": "netcoreapp3.1",
            "defaultValue": "netcoreapp3.1"
        }
    }
}
```

We can also create a second symbol similar to the sourceName param that replaces a value in the template files. The UmbracoNineDemoSite has Products that has controllers, a composer, view models - etc. Let's say we use this as a baseline for different shop sites and this new site is going to be about selling Sofas - we may want to replace `Product` with `Sofa` then:

_Right below the Framework symbol we add the new ProductName param:_

```json
"symbols": {
    "Framework": {
        "type": "parameter",
        "description": "The target framework for the project.",
        "datatype": "choice",
        "choices": [
            {
                "choice": "netcoreapp3.1",
                "description": "Target netcoreapp3.1"
            }
        ],
        "replaces": "netcoreapp3.1",
        "defaultValue": "netcoreapp3.1"
    },
    "ProductName": {
        "type": "parameter",
        "defaultValue": "",
        "replaces": "Product",
        "datatype":"text",
        "fileRename": "Product",
        "description": "Product to be replaced"
    }
}
```

WARNING: This could mess up your site if you use something too generic, `Product` is a terrible example - please use something that is way more specific!

Note that the `replaces` value is for within files, whereas the `fileRename` value is for actual filenames being changed, so you have a bit of granular control if you only want one type.

At this point we can reset and reinstall the template:

```
Reset-Templates; dotnet new --install ..\BoilerPlate\
```

Now we can see the new param in the help description by running:

```
dotnet new test-bp --help
```

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7gxbsoqk8ubqd9pahjge.png)
 
Let's install it while using the new param:

```
dotnet new test-bp -o MyTestSiteTwo --ProductName Sofa
```

If you open and compare your solution you can now see that filenames, namespace, etc have all been changed:

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7tg04bn9311wusu8755r.png)
 
## Closing note

There are lots more you can do, but will leave it at this for part 1. I hope this gave a good first view of setting up your own dotnet templates!

Thanks for reading! If you like this post, have any feedback, suggestions, improvements to my hacky code or anything else please let me know on Twitter - [@jespermayn](https://twitter.com/JesperMayn)