adoconnection / RazorEngineCore

.NET6 Razor Template Engine
MIT License
585 stars 88 forks source link

Can't get extension methods to work #71

Closed afelsing closed 3 years ago

afelsing commented 3 years ago

Hello! I am coming across an issue where extension methods are not being identified properly. In my sample below, I am trying to use LINQ's single, and the error is:

'System.Collections.Generic.List' does not contain a definition for 'First'

I've added the required assemblies using AddAssemblyReferenceByName() and assume it would load correctly. Yet I'm still getting the error.

When I call the extension method fully qualified, it works. ie, calling System.Linq.First(myList) instead of myList.Single().

Any guidance would be greatly appreciated!

Sample code:

class Program
{
    static string Content = @"
        Hello @Model.Name

        First item: @Model.Items.First();

        @foreach(var item in @Model.Items)
        {
            <div>- @item</div>
        }

        <div data-name=""@Model.Name""></div>

        <area>
            @{ RecursionTest(3); }
        </area>

        @{
            void RecursionTest(int level){
                if (level <= 0)
                {
                    return;
                }

                <div>LEVEL: @level</div>
                @{ RecursionTest(level - 1); }
            }
        }";

    static void Main(string[] args)
    {
        IRazorEngine razorEngine = new RazorEngine();
        IRazorEngineCompiledTemplate template = razorEngine.Compile(Content,
            builder =>
            {
                builder.AddAssemblyReferenceByName("System.Collections");
                builder.AddAssemblyReferenceByName("System.Linq");
            });

        string result = template.Run(new
        {
                Name = "Alexander",
                Items = new List<string>()
                {
                        "item 1",
                        "item 2"
                }
        });

        Console.WriteLine(result);
        Console.ReadKey();
    }
}
adoconnection commented 3 years ago

Hi, have a look at this unit test. When using dynamic model, you have to cast property to IEnumerable / ICollection / IList https://github.com/adoconnection/RazorEngineCore/blob/a2ae1f17de9553be86789d57b1d33b16df969a54/RazorEngineCore.Tests/TestCompileAndRun.cs#L540

            RazorEngine razorEngine = new RazorEngine();
            IRazorEngineCompiledTemplate template = razorEngine.Compile(
@"
@foreach (var item in ((IEnumerable<object>)Model.Numbers).OrderByDescending(x => x))
{
    <p>@item</p>
}
");
            string expected = @"
    <p>3</p>
    <p>2</p>
    <p>1</p>
";
            string actual = template.Run(new
            {
                    Numbers = new List<object>() {2, 1, 3}
            });

            Assert.AreEqual(expected, actual);
afelsing commented 3 years ago

Wonderful! Thank you much.