Question

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

Was it helpful?

Solution

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.

OTHER TIPS

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);
            }                
 }

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

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;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top