It appears RazorEngine can't access nested anonymous types...here is the test I was running. It basically can't find fields in the objects part of model.Members below. Any ideas why it would be?
[TestMethod]
public void SimplestRazorEngineWithAnonymousComplexModelTest()
{
var hisStuff = new [] {"A", "B", "C"};
var herStuff = new[] { "X", "Y" };
var model = new
{
Name = "Couple",
Company = "ACME",
Members = new [] {
new
{
Name = "Joe Doe",
Company = "West Wind",
Collection = hisStuff
},
new
{
Name = "Jane Doe",
Company = "East Wind",
Collection = herStuff
}
}
};
string template = @"Hello World @Model.Name of @Model.Company. Time is: @DateTime.Now";
template += @"@foreach (var person in Model.Members) @person.Name}";
var host = new RazorEngine<RazorTemplateBase>();
string cid = host.CompileTemplate(template);
if (null == cid)
{
Console.WriteLine(cid + "\r\n" +
host.ErrorMessage + "\r\n" +
host.LastGeneratedCode);
}
else
{
string result = host.RenderTemplateFromAssembly(cid, model);
Console.WriteLine(result + "\r\n" +
host.ErrorMessage + "\r\n" +
host.LastGeneratedCode);
Assert.IsTrue(result.Contains("Joe Doe"));
}
}
Anonymous types are private to the scope they are declared in so I wouldn't expect them to be visible in the model externally in a Razor page. Externally they are exposes as object
. Have you tried this in a proper MVC or RazorPage application? I would expect that to not work there either.
It works in your test because the declaration and call are in scope.
If you want to use those values you have scope them to dynamic
and then it would work I believe.
+++ Rick ---
To demonstrate try this in LinqPad:
void Main()
{
var hisStuff = new[] { "A", "B", "C" };
var herStuff = new[] { "X", "Y" };
var model = new
{
Name = "Couple",
Company = "ACME",
Members = new[] {
new
{
Name = "Joe Doe",
Company = "West Wind",
Collection = hisStuff
},
new
{
Name = "Jane Doe",
Company = "East Wind",
Collection = herStuff
}
}
};
Output(model);
}
// Notice the only way you can pass this is as 'object' or 'dynamic'
public void Output(dynamic model)
{
foreach (var person in model.Members)
{
// works but only as 'dynamic' (or object)
Console.WriteLine(person.Company);
}
}
Notice how in the Output method you lose the scope of the object. In the Razor Engine when you call RenderTemplateFromAssembly()
and pass the model, you lose the typing and it becomes object
or dynamic
.
You are correct, the code snippet works fine. At first it seemed that since the engine can get to the top level anonymous type members it should also be able to get to members that are anonymous themselves...Thanks.