Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Building a dynamic JSON response in MVC 5 - How to tack on properties to a result set?

I am returning an array of objects to a page that renders a slideshow based on a photo album.

I fetch my pictures from the database.

Before I return this array as a result, I would like to tack on a "Thumbnail" url property. This property does not exist on the AlbumPicture, but I want it in the response.

This illustrates the idea:

List<AlbumPicture> pics = db.AlbumPictures.Where(p => p.AlbumID == album.ID).OrderBy(p => p.RankOrder).ToList();
foreach(AlbumPicture p in pics)
{
    p.AddPropertyThatDoesntExist("Thumbnail", ThumbManager.GetThumb(p.ID));
}

return Json(pics, JsonRequestBehavior.AllowGet);

What is the most elegant way to add this JSON field to my result set?

This question is so basic that it is probably a duplicate. However, I googled for 10 minutes and could only find janky solutions that depend on 3rd party libraries. I'm interested in the current "best practice".

Possible duplicate of: How to add dynamically more properties to Json response from the controller. However, that answer will make the dynamically added fields uncles instead of siblings to my AlbumPicture properties in the resulting JSON.

like image 683
John Shedletsky Avatar asked Jan 15 '15 01:01

John Shedletsky


1 Answers

Currently, C# 4.0 support dynamic object, so you can use dynamic object to add your properties as run time.

First, add this extension method to your code:

public static class DynamicExtensions
{
    public static dynamic ToDynamic(this object value)
    {
        IDictionary<string, object> expando = new ExpandoObject();

        foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(value.GetType()))
            expando.Add(property.Name, property.GetValue(value));

        return expando as ExpandoObject;
    }
}

And then, change your code to something like this

var pics = db.AlbumPictures.Where(p => p.AlbumID == album.ID)
          .OrderBy(p => p.RankOrder)
          .Select(p=> 
                  { dynamic copy = p.ToDynamic();
                    copy.Thumbnail = ThumbManager.GetThumb(p.ID); //You can add more dynamic properties here
                    return copy;
                  })
          .ToList();

return Json(pics, JsonRequestBehavior.AllowGet);
like image 162
Huy Hoang Pham Avatar answered Sep 21 '22 13:09

Huy Hoang Pham