C# Dotliquid string templates

Date: 2021-03-22

Language syntax documentation: https://shopify.github.io/liquid/

// Create a Hash, containing all data usable by the template
var json = JsonConvert.SerializeObject(model);
var dictionary = JsonConvert.DeserializeObject<Dictionary<string, object>>(json, new DictionaryConverter());
var hash = Hash.FromDictionary(dictionary);

var template = Template.Parse(TemplateString);  // Parses and compiles the template
var content = template.Render(hash); // Executes the variable replacement in the template
using Newtonsoft.Json;

public class DictionaryConverter : JsonConverter
{
	public override bool CanWrite => false;
	public override bool CanConvert(Type objectType) => typeof(IDictionary<string, object>).IsAssignableFrom(objectType);
	public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { }
	public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) => ReadValue(reader);

	private object ReadValue(JsonReader reader)
	{
		while (reader.TokenType == JsonToken.Comment)
		{
			if (!reader.Read()) throw new JsonSerializationException("Unexpected Token when converting IDictionary<string, object>");
		}
		switch (reader.TokenType)
		{
			case JsonToken.StartObject:
				return ReadObject(reader);
			case JsonToken.StartArray:
				return this.ReadArray(reader);
			case JsonToken.Integer:
			case JsonToken.Float:
			case JsonToken.String:
			case JsonToken.Boolean:
			case JsonToken.Undefined:
			case JsonToken.Null:
			case JsonToken.Date:
			case JsonToken.Bytes:
				return reader.Value;
			default:
				throw new JsonSerializationException
					(string.Format("Unexpected token when converting IDictionary<string, object>: {0}", reader.TokenType));
		}
	}

	private object ReadArray(JsonReader reader)
	{
		IList<object> list = new List<object>();
		while (reader.Read())
		{
			switch (reader.TokenType)
			{
				case JsonToken.Comment:
					break;
				default:
					var v = ReadValue(reader);
					list.Add(v);
					break;
				case JsonToken.EndArray:
					return list;
			}
		}
		throw new JsonSerializationException("Unexpected end when reading IDictionary<string, object>");
	}

	private object ReadObject(JsonReader reader)
	{
		var obj = new Dictionary<string, object>();
		while (reader.Read())
		{
			switch (reader.TokenType)
			{
				case JsonToken.PropertyName:
					var propertyName = reader.Value.ToString();
					if (!reader.Read())
					{
						throw new JsonSerializationException("Unexpected end when reading IDictionary<string, object>");
					}
					var v = ReadValue(reader);
					obj[propertyName] = v;
					break;
				case JsonToken.Comment:
					break;
				case JsonToken.EndObject:
					return obj;
			}
		}
		throw new JsonSerializationException("Unexpected end when reading IDictionary<string, object>");
	}
}
using System;
using System.Collections.Generic;
using System.Linq;
using Domain.Models;

namespace {{ Namespace }}
{
	public class Dm{{ Name }}
	{
{% for p in Properties -%}
		public {{ p.DataType }} {{ p.Name }} { get; set; }
{% endfor -%}

		internal static Dm{{Name}} FromDomain({{Name}} src)
		{
			if (src == null) return null;
			return new Dm{{Name}} {
{% for p in Properties -%}
				{{ p.Name }} = src.{{ p.Name }}{% if forloop.index != Properties.size %},{% endif -%} 
{% endfor -%} 
			};
		}
		internal static {{Name}} ToDomain(Dm{{Name}} src)
		{
			if (src == null) return null;
			return new {{Name}} {
{% for p in Properties -%}
				{{ p.Name }} = src.{{ p.Name }}{% if forloop.index != Properties.size %},{% endif -%} 
{% endfor -%} 
			};
		}
	}
}
47310cookie-checkC# Dotliquid string templates