21

This is probably a silly question, but I am trying to stuff an anonymous object in ViewBag like so:

ViewBag.Stuff = new { Name = "Test", Email = "user@domain.com" };

and access it from a View like so:

@ViewBag.Stuff.Name

I understand ViewBag is dynamic and that "Stuff" is an anonymous object... but when I look with the debugger from the View line above, I can see all the properties with the proper values. Why does the model binder have such a hard time with this?

Is there a good way to accomplish this without creating a model class? I want to continue using new {}

one.beat.consumer
  • 9,414
  • 11
  • 55
  • 98
  • 1
    can you use @ViewBag.Stuff.Name or @ViewBag.Stuff.Email?? Cause Test is a value and not a key/property – SynerCoder Jan 23 '12 at 23:42
  • That was a typo and has been fixed. I have been trying to access the properties, not their values. Thanks. – one.beat.consumer Jan 23 '12 at 23:44
  • Turns out, this cannot be done. See this: http://stackoverflow.com/questions/5649536/entity-framework-select-new. – SoWeLie Jan 24 '12 at 00:15
  • @SoWeLie thanks for digging that up. I just edited it to make it easier to find for the next person... edit your answer with this link and summarize the thing about "internal" and i'll mark you as answer. – one.beat.consumer Jan 24 '12 at 00:49

4 Answers4

10

Essentially the issue is that anonymous types are generated as internal (see answer), making hard typed references to the object's property impossible from the View. This article provides a more detailed explanation:

http://www.heartysoft.com/anonymous-types-c-sharp-4-dynamic

It is possible to accomplish with the use of a Dynamic Anonymous wrapper class (@Dakill's answer), but gets ugly fast and should make a programmer question why he/she would do so.

Community
  • 1
  • 1
SoWeLie
  • 1,381
  • 12
  • 16
  • I'm looking for an answer on if it can be done, and if not, why... (didn't downvote you btw) – one.beat.consumer Jan 23 '12 at 23:53
  • So, I'll give you another answer then. However, I still stand by this answer as what you should do if you're trying to build a maintainable application. – SoWeLie Jan 24 '12 at 00:13
5

Contrary to popular belief, this can be done, but involves a somewhat ugly hack that will lead to maintenance problems down the road.. It involves writing a class to "wrap" your anonymous object into a dynamic object. I've made it as an exercise some time ago, below is the code to the wrapper class, you would use it like ViewBag.Stuff = new DynamicAnonymous(new { Name = "Test", Email = "user@domain.com" });..

public class DynamicAnonymous : DynamicObject
{
            object obj;

            public DynamicAnonymous(object o)
            {
                    this.obj = o;
            }

            public override IEnumerable<string> GetDynamicMemberNames()
            {
                    return obj.GetType().GetProperties().Select(n => n.Name);
            }

            public override bool TryGetMember(GetMemberBinder binder, out object result)
            {
                    var prop = obj.GetType().GetProperty(binder.Name);
                    if (prop == null)
                    {
                            result = null;
                            return false;
                    }
                    else
                    {
                            result = prop.GetValue(obj, null);
                            return true;
                    }
            }

            public override int GetHashCode()
            {
                    return obj.GetHashCode();
            }

            public override string ToString()
            {
                    return obj.ToString();
            }

            public override bool Equals(object obj2)
            {
                    return obj.Equals(obj2);
            }                
 }
3

we can lovely accomplish that using Json

Controller : object -> json string , View : Json string -> object

The scenerio is simply the controller class serialize the C# object into json string then later the view receives this string and deserializes it to an object , like so :

in Controller :

using Newtonsoft.Json;
ViewBag.Stuff = JsonConvert.SerializeObject(new { Name = "Test", Email = "user@domain.com" });

in View :

@using Newtonsoft.Json
<p>@JsonConvert.DeserializeObject(ViewBag.Stuff).Name</p>

Note : this was tested in Asp.Net Core 2.2 , Check that link to install Newtonsoft.Json

Mawardy
  • 3,618
  • 2
  • 33
  • 37
  • Are there any performance issues with the above approach ? Is it better to use a strongly typed `Model` structure for such cases? – Rahul Sharma Oct 19 '22 at 19:16
0

You can do it using the mechanism NothingsImpossible descibed, but withou implementing your own wrapper using ExpandoObject. Here is an Example:

var items = _repository.GetItems()
    .Select(og => {
        dynamic eo = new System.Dynamic.ExpandoObject();
        eo.Id = item.Id;
        eo.FriendlyName = og.FriendlyName;
        eo.Selected = itemIds.Contains(item.Id);
        return eo;
    })
    .ToArray();
ViewBag.Items = items;
Glia
  • 371
  • 2
  • 9