West Wind Internet and Client Tools
handling nested anonymous types
Gravatar is a globally recognized avatar based on your email address. handling nested anonymous types
  Carlos Manuel Diaz-Perez
  All
  Jan 20, 2020 @ 10:53am

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"));
            }
        }
Gravatar is a globally recognized avatar based on your email address. re: handling nested anonymous types
  Rick Strahl
  Carlos Manuel Diaz-Perez
  Jan 21, 2020 @ 12:26pm

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 ---

Gravatar is a globally recognized avatar based on your email address. re: handling nested anonymous types
  Rick Strahl
  Carlos Manuel Diaz-Perez
  Jan 21, 2020 @ 12:37pm

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.

Gravatar is a globally recognized avatar based on your email address. re: handling nested anonymous types
  Carlos Manuel Diaz-Perez
  Rick Strahl
  Jan 24, 2020 @ 01:26pm

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.

Gravatar is a globally recognized avatar based on your email address. re: handling nested anonymous types
  Rick Strahl
  Carlos Manuel Diaz-Perez
  Jan 24, 2020 @ 06:11pm

It can, but you have to explicitly cast your template's model to dynamic (or no model header at all in which case that should be automatic) and then it should work.

+++ Rick ---

© 1996-2020