I would like to render a Scriban template with an ExpandoObject
or any other data type that can be generated from a JSON string:
var json = "....";
var dyn = JsonConvert.DeserializeObject<ExpandoObject>(json);
var template = Scriban.Template.Parse("Hello {{ data.foo }}!");
var result = template.Render(dyn);
Scriban does not work with ExpandoObject
s, as they are parsed as a list of { key = '', value = '' }
objects. Declaring a type for the data is not an option in my use case as the JSON schema is not known a priori.
Casting ExpandoObject to dynamic shows the same behavior as using ExpandoObject
directly.
I've tried deserializing the JSON to dynamic
which leads to an exception:
System.Reflection.TargetParameterCountException: "Parameter count mismatch."
Can I somehow convert the data or configure Scriban to render dynamic data?
Based on the previous answer this is a solution for complex objects:
public static class ScribanRenderer
{
public static string RenderJson(string json, string content)
{
var expando = JsonConvert.DeserializeObject<ExpandoObject>(json);
var sObject = BuildScriptObject(expando);
var templateCtx = new Scriban.TemplateContext();
templateCtx.PushGlobal(sObject);
var template = Scriban.Template.Parse(content);
var result = template.Render(templateCtx);
return result;
}
private static ScriptObject BuildScriptObject(ExpandoObject expando)
{
var dict = (IDictionary<string, object>) expando;
var scriptObject = new ScriptObject();
foreach (var kv in dict)
{
var renamedKey = StandardMemberRenamer.Rename(kv.Key);
if (kv.Value is ExpandoObject expandoValue)
{
scriptObject.Add(renamedKey, BuildScriptObject(expandoValue));
}
else
{
scriptObject.Add(renamedKey, kv.Value);
}
}
return scriptObject;
}
}
It leverages the fact that complex properties of an ExpandoObject
are always ExpandoObjects
when it gets deserialized from JSON. It recursively adds ScriptObjects
for complex member types and the object itself for all other properties to the ``ScriptObject`.
Please note that my solution uses Scriban's default member renaming, where FirstName
becomes first_name
and so on.