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