Storing an Anonymous Object in ViewBag
Asked Answered
B

4

22

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

Betoken answered 23/1, 2012 at 23:20 Comment(4)
can you use @ViewBag.Stuff.Name or @ViewBag.Stuff.Email?? Cause Test is a value and not a key/propertyPrae
That was a typo and has been fixed. I have been trying to access the properties, not their values. Thanks.Betoken
Turns out, this cannot be done. See this: https://mcmap.net/q/589211/-stuffing-an-anonymous-type-in-viewbag-causing-model-binder-issues.Beniamino
@Beniamino 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.Betoken
B
11

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.

Beniamino answered 23/1, 2012 at 23:47 Comment(2)
I'm looking for an answer on if it can be done, and if not, why... (didn't downvote you btw)Betoken
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.Beniamino
L
6

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);
            }                
 }
Laryssa answered 24/1, 2012 at 1:3 Comment(0)
S
4

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

Stenopetalous answered 13/1, 2019 at 20:29 Comment(1)
Are there any performance issues with the above approach ? Is it better to use a strongly typed Model structure for such cases?Flaherty
M
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;
Moratorium answered 27/1, 2017 at 8:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.