Using dynamic object in ASP.NET Core MVC view

1.7k Views Asked by At

Let me start by saying that I know there are other ways to do this and I have already successfully done it other ways. But I got to wondering how to use @model IEnumerable<dynamic> in a view.

I have tried this in the controller:

var result = from p in _db.People
             join ps in _db.PersonSport on p.PersonId equals ps.PersonIdfk
             join s in _db.Sports on ps.SportCodeFk equals s.SportCode
             orderby s.SportName
             where p.LastName == "Orr"
             select new { p.FirstName, p.LastName, s.SportName };
return View(result);

With this in the view:

@model IEnumerable<dynamic>
<h4>Sports played by @Model.First().FirstName @Model.First().LastName:</h4>
   @foreach (var item in Model) {
       @item.SportName;<br />
    }

And I get a runtime error

RuntimeBinderException: 'object' does not contain a definition for 'FirstName'

A breakpoint at the <h4> shows that model has the data:

Auto variable showing expanded Model in View

I tried using creating result as a new ExpandoObject() and got the same error.

Am I way off base here or attempting something impossible? I was thinking of a use case where you have many table columns but are only extracting a few. Yes, I know I could create a class and do it that way, or send the data in ViewModel/ViewData, but was wondering if this was an option.

1

There are 1 best solutions below

0
On

The short answer is that using anonymous types is not supported, however, there is a workaround, you can use an ExpandoObject.

The whole working demo is like below:

  1. Custom ToExpando method:
public static class Extension
{
    public static IEnumerable<dynamic> ToExpando(this IEnumerable<object> anonymousObject)
    {
        IList<dynamic> list = new List<dynamic>();

        foreach (var item in anonymousObject)
        {
            IDictionary<string, object> anonymousDictionary = HtmlHelper.AnonymousObjectToHtmlAttributes(item);
            IDictionary<string, object> expando = new ExpandoObject();

            foreach (var nestedItem in anonymousDictionary)
                 expando.Add(nestedItem);

            list.Add(expando);
        }

        return list.AsEnumerable();
    }
}
  1. View:
    @model IList<dynamic>
    <table class="table">
        <thead>
            <tr>
                <th>FirstName</th>
                <th>LastName</th>
                <th>SportName</th>
            </tr>
        </thead>
        @foreach (var item in Model)
        {
            <tr>
                <td>
                    @item.FirstName
                </td>
                <td>
                    @item.LastName
                </td> 
                <td>
                    @item.SportName
                </td>
            </tr>
    
        }
    </table>
  1. Controller:
public IActionResult Index()
{
    var result = (from p in _db.People
             join ps in _db.PersonSport on p.PersonId equals ps.PersonIdfk
             join s in _db.Sports on ps.SportCodeFk equals s.SportCode
             orderby s.SportName
             where p.LastName == "Orr"
             select new { p.FirstName, p.LastName, s.SportName }
             ).ToExpando().ToList();
    return View(result);
}

Result:

enter image description here