Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Storing an Anonymous Object in ViewBag

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 = "[email protected]" };

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 {}

like image 310
one.beat.consumer Avatar asked Jan 23 '12 23:01

one.beat.consumer


3 Answers

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.

like image 127
SoWeLie Avatar answered Nov 07 '22 00:11

SoWeLie


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 = "[email protected]" });..

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);
            }                
 }
like image 44
NothingsImpossible Avatar answered Nov 06 '22 23:11

NothingsImpossible


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 = "[email protected]" });

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

like image 3
Mawardy Avatar answered Nov 07 '22 00:11

Mawardy