Dynamic input in Templated Razor Delegates - ASP.Net Core Razor Pages

Shervan360 1,681 Reputation points
2023-07-14T18:25:38.83+00:00

Hello,

The input parameter in the following Templated Razor Delegate is dynamic. I expected I didn't have any errors before executing the program. because it is a dynamic type and it execute at run time if we misspell the name.

citieis

@page
@model WebApplication1.Pages.WelcomeModel
@{
     Func<dynamic, object> myUnorderedListTemplate =
               @<ul>
               @foreach (var item in cities)
               {
                    <li>@item.Name</li>
               }
     </ul>;
}
@myUnorderedListTemplate(citiesA) @*when added A to cities, the compiler got an error. 
            The variable is dynamic and I did not expect the error before execution.*@
@functions {
     public class City
     {
          public string Name { get; set; }
          public string Country { get; set; }
     }
     List<City> cities = new List<City>{
        new City { Name = "London", Country = "UK" },
        new City { Name = "Paris", Country = "France" },
        new City { Name = "Rome", Country = "Italy" }
    };
}
Developer technologies | ASP.NET | ASP.NET Core
0 comments No comments
{count} votes

3 answers

Sort by: Most helpful
  1. AgaveJoe 30,491 Reputation points
    2023-07-14T19:44:51.0633333+00:00

    The loop pattern is...

    Func<dynamic, object> myUnorderedListTemplate =
        @<ul>
        @foreach (var i in item)
        {
            <li>@i.Name</li>
        }
        </ul>;
    

  2. Bruce (SqlWork.com) 82,146 Reputation points Volunteer Moderator
    2023-07-15T03:05:56.72+00:00

    dynamic is similar to object in that its type can be changed. what's different is that the properties and methods are executed at runtime via reflection.

    in your code:

    Func<dynamic, object> myUnorderedListTemplate =
         @<ul>
         @foreach (var item in cities). 
         {
             <li>@item.Name</li>
         }
         </ul>;
    

    you have a couple of issues:

    • the variable cities is not a parameter, just a undefined variable.
    • also the razor html syntax is not supported in a function definition.

    while a helper is cleaner, you can:

    Func<IEnumerable<dynamic>, HtmlString> myUnorderedListTemplate = (cities) =>
    {
        var html = "<ul>";
        foreach (var item in cities)
        {
           html += $"<li>{System.Web.HttpUtility.HtmlEncode(item.Name)}</li>";
        }
        html += "</ul>";
        return new HtmlString(html);
    };
    

    though as the function needs to know the property names, not sure why dynamic.

    in your code calling the function the variable citiesA is undefined.

    @myUnorderedListTemplate(citiesA)
    
    0 comments No comments

  3. Qing Guo - MSFT 896 Reputation points Microsoft External Staff
    2023-07-17T08:48:45.5466667+00:00

    Hi @Shervan360 ,

    Func<dynamic, object>

    The input parameter represents data and is a dynamic type, the data is accessible within the template through a parameter named item. When you pass citiesA, you need to define citiesA first, the full code like :

    @page
    @model WebApplication1.Pages.WelcomeModel
    @{
         Func<dynamic, object> myUnorderedListTemplate =
                   @<ul>
                   @foreach (var city in item)
                   {
                        <li>@city.Name</li>
                   }
         </ul>;
    }
    @myUnorderedListTemplate(citiesA) @*when added A to cities, the compiler got an error. 
                The variable is dynamic and I did not expect the error before execution.*@
    @functions {
         public class City
         {
              public string Name { get; set; }
              public string Country { get; set; }
         }
         List<City> cities = new List<City>{
            new City { Name = "London", Country = "UK" },
            new City { Name = "Paris", Country = "France" },
            new City { Name = "Rome", Country = "Italy" }
        };
        List<City> citiesA = new List<City>{
            new City { Name = "London", Country = "UK" },
            new City { Name = "Paris", Country = "France" }        
        };
    }
    

    result:

    2


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    Best regards,

    Qing Guo

    0 comments No comments

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.