# Handlebars.Net &#038; JSON templates

**Date:** 2022-09-17  
**Author:** Kees C. Bakker  
**Categories:** .NET / C#  
**Tags:** Handlebars  
**Original:** https://keestalkstech.com/handlebars-net-json-templates/

![Handlebars.Net &#038; JSON templates](https://keestalkstech.com/wp-content/uploads/2022/09/dan-gold-_BaWRZMLq8I-unsplash.jpg)

---

I ♥️ Handlebars! So I was very very very happy to see that [Handlebars was ported to .NET](https://github.com/Handlebars-Net/Handlebars.Net)! It is a mega flexible templating engine as it can easily be extended. I'm working on a project where I need to parse objects via JSON templates to JSON strings. This article will show how to instruct Handlebars to parse into JSON and add some nice error messages if your template fails.

## Encoding JSON text

The trick is to add a special `ITextEncoder` to the `IHandlebars` instance. I've created a `JsonTextEncoder` that will do the proper escaping:

[include-github-code src="https://github.com/KeesCBakker/keestalkstech-code-gallery/blob/main/06.handlebars/Ktt.JsonHandlebars/JsonTextEncoder.cs" wide=true usings="false" namespace="false"]

I've added some extra methods for convenience.

### Example

You can use the static class to parse JSON templates and receive a JSON string back:

```cs
string source =
@"
{ 
  ""title"": ""{{title}}"",
  ""body"": ""{{body}}""
}";

var template = JsonHandlebarsDotNet.Compile(source);

var data = new
{
    title = "My new post",
    body = "This\nis\nmy \"first post\"!"
};

var result = template(data);

/* result is: 
{
  "title": "My new post",
  "body": "This\nis\nmy \"first post\"!"
}
*/
```

## Improve JSON debugging

Debugging those JSON results is quite a challenge, as it is super easy to forget a comma. So we need something to help us detect validation errors quickly. Let's add a new method that also parses the result and wraps any exception:

```cs
public static string Parse(string template, object input)
{
    var t = Compile(template);
    var json = t(input);

    try
    {
        JsonConvert.DeserializeObject<dynamic>(json);
    }
    catch (Exception ex)
    {
        throw new InvalidJsonException(ex, json);
    }

    return json;
}
```

Let's implement the `InvalidJsonException` class that parsed the message of the exception that was thrown:

[include-github-code src="https://github.com/KeesCBakker/keestalkstech-code-gallery/blob/main/06.handlebars/Ktt.JsonHandlebars/InvalidJsonException.cs" wide=true usings="false" namespace="false" buster=1]

Now our errors contain a visual representation of where the error is, making debugging a lot easier. Here we have an example of a template containing the error. We've omitted a `,` between the .NET and C# tags.

```cs
string source =
@"
{ 
  ""title"": ""{{title}}"",
  ""author"": ""Kees C. Bakker"",
  ""authorUrl"": ""https://keestalkstech.com/about-me/"",
  ""created"": ""2202-09-17 11:52"",
  ""categories"": [ ""programming"" ],
  ""tags"": [ "".NET"" ""C#"", ""HBS"" ],
  ""body"": ""{{body}}""
}";

var data = new
{
    title = "My new post",
    body = "First!"
};

try
{
    var json = JsonHandlebarsDotNet.Parse(source, data);
    Console.WriteLine(json);
}
catch (Exception ex)
{
    Console.WriteLine(ex.Message);
}
```

When we execute the code, we'll get the following error message:

```txt
After parsing a value an unexpected character was encountered: ". Path 'tags[0]', line 8, position 21.

06 |  "created": "2202-09-17 11:52",
07 |  "categories": [ "programming" ],
08 |  "tags": [ ".NET" "C#", "HBS" ],
-----------------------^
09 |  "body": "First!"
10 | }
```

One might consider pre-parsing the template for errors, but that won't help you, because the template might have perfectly valid handlebar tags, which are invalid in JSON.

## Inject a JSON Template Generator

While a static class will work for many use cases, it might be better to use *dependency injection*. Let's create a `IJsonTemplateGenerator`:

[include-github-code src="https://github.com/KeesCBakker/keestalkstech-code-gallery/blob/main/06.handlebars/Ktt.JsonHandlebars/IJsonTemplateGenerator.cs" wide=true usings="false" namespace="false"]

This object has everything to help us in parsing templates:

- `Handlebars` to which the user could add custom helper extensions.
- `Compile` to compile a string template and use it later on.
- `Parse` to parse a template with data into a JSON string. This method should do the validation as well.
- `ParseToObject` to parse a template with data and deserialize the result into a dynamic object.

Now, let's implement it:

[include-github-code src="https://github.com/KeesCBakker/keestalkstech-code-gallery/blob/main/06.handlebars/Ktt.JsonHandlebars/JsonTemplateGenerator.cs" wide=true usings="false" namespace="false"]

## Manifest streams: templates as embedded resources

I would like to ship my templates as an *embedded resource* with the DLL. So let's create some extension methods to help us to

[include-github-code src="https://github.com/KeesCBakker/keestalkstech-code-gallery/blob/main/06.handlebars/Ktt.JsonHandlebars/JsonTemplateGeneratorExtensions.cs" wide=true usings="false" namespace="false" buster=1]

[include-github-code src="https://github.com/KeesCBakker/keestalkstech-code-gallery/blob/main/06.handlebars/Ktt.JsonHandlebars/ManifestResourceNotFoundException.cs" wide=true usings="false" namespace="false" buster=2]

We can now use these methods to read templates directly from our DLL:

```cs
var template = _generator.ParseWithManifestResourceToObject( 
    "BotZero.Handlers.Templates.Poker.json.hbs",
    vote);
```

## Changelog

- 2026-07-20: Updated code and tests to .NET 10. Refactored JsonTextEncoder into a separate file and applied code review fixes.
- 2024-12-01: the code is now compatible with .NET 8 and added to the gallery.
- 2022-09-24: added extension methods to parse manifest files.
- 2022-09-24: added the `IJsonTemplateGenerator` for dependency injection.
- 2022-09-24: added a `ParseToObject` to get a dynamic deserialized object.
- 2022-09-18: added line numbers to exception. ~~Added a `ValidateJson` method to the final class.~~
- 2022-09-17: initial article.

I've added the code to my .NET gallery, check: [keestalkstech-code-gallery/06.handlebars](https://github.com/KeesCBakker/keestalkstech-code-gallery/tree/main/06.handlebars).
