0

I have a code that I've written which looks like this:

    ViewBag.Items = user.Items.GroupBy(x => x.ItemId).Select(pr => new
            {
                ItemId = pr.Key,
                ImageURL = pr.Select(x=>x.ImageURL).FirstOrDefault(),
                Title = pr.Select(x=>x.Title).FirstOrDefault(),
                Sales = pr.Select(x=>x.Transactions.Sum(y=>y.QuantitySold))

            }).ToList();

As you can see it's a list of anonymous objects... What I'm trying to do now is to bind these values into my already existing view like this:

     <tbody>
                @if (ViewBag.Items != null)
                {
                    foreach (var item in ViewBag.Items)
                    {
                        <tr>
                            <td><img src="@item.ImageURL" /></td>
                            <td>@item.Title</td>
                            <td>@item.Sales</td>
                        </tr>
                    }
                }
            </tbody>

But I'm getting this error:

Additional information: 'object' does not contain a definition for 'ImageURL'

And for other properties as well...

How can I fix this, but to in same time avoid creating extra class that would make the view strongly types.. Can someone help me out ?

Cœur
  • 37,241
  • 25
  • 195
  • 267
User987
  • 3,663
  • 15
  • 54
  • 115
  • For that to work you'd need to cast to dynamic `foreach(dynamic item in...` but it would be much better to create a custom class instead of using an anonymous one. – juharr Apr 24 '17 at 12:45
  • @juharr any specific reason to make a custom class? I'm trying to make my code as much as it can be minimalistic and simple... – User987 Apr 24 '17 at 12:45
  • @juharr with foreach(dynamic item in...) still getting the same exception .. – User987 Apr 24 '17 at 12:46
  • 2
    By using dynamic you'll be relying on runtime type checking instead of compile time. Strong types are one of the best things about C#. – juharr Apr 24 '17 at 12:47
  • 1
    @User987 Because a custom class is easier to work with, and provides the security of the presence of the properties you're expecting. If you need to change things down the line, you might forget to change one in the View. – krillgar Apr 24 '17 at 12:47
  • 1
    Create a view model (but as a poor option you can use `dynamic` - refer [this answer](http://stackoverflow.com/questions/6612938/razor-view-with-anonymous-type-model-class-it-is-possible) or use the non-typed `HtmlHelper` methods - refer [this answer](http://stackoverflow.com/questions/223713/can-i-pass-an-anonymous-type-to-my-asp-net-mvc-view)) –  Apr 24 '17 at 12:48
  • 1
    You could always use an interface instead if you want to be able to use this view with more than one class that has the same set of properties. – juharr Apr 24 '17 at 12:48
  • @juharr yes this is exactly what I wanted! Great thanks for the advice :) – User987 Apr 24 '17 at 12:49

2 Answers2

3

It is becuase ViewBag is a dynamic type and using it we lose the comiple time safety and intellisense, what you can do it create a ViewModel and use that :

public class ViewModel
{
   public int ItemId {get;set;}
   ...
   ...
   ...
}

and then project on that viewmodel :

var model = user.Items.GroupBy(x => x.ItemId).Select(pr => new
        ViewModel {
                ItemId = pr.Key,
                ImageURL = pr.Select(x=>x.ImageURL).FirstOrDefault(),
                Title = pr.Select(x=>x.Title).FirstOrDefault(),
                Sales = pr.Select(x=>x.Transactions.Sum(y=>y.QuantitySold))

        }).ToList();

return View(model);

now in your view bind your view to that model like:

@model List<YourNamespace.ViewModels.ViewModel>
@if (@Model!= null)
{
     foreach (var item in @Model)
     {
         <tr>
            <td><img src="@item.ImageURL" /></td>
            <td>@item.Title</td>
            <td>@item.Sales</td>
         </tr>
     }
}
Ehsan Sajjad
  • 61,834
  • 16
  • 105
  • 160
0

just cast it to the target type

<tbody>
            @if (ViewBag.Items != null)
            {
                foreach (var item in (List<Items>)ViewBag.Items)
                {
                    <tr>
                        <td><img src="@item.ImageURL" /></td>
                        <td>@item.Title</td>
                        <td>@item.Sales</td>
                    </tr>
                }
            }
        </tbody>
Syed Mhamudul Hasan
  • 1,341
  • 2
  • 17
  • 45