简体   繁体   中英

ASP.NET MVC4 Web API - Control over formatting of returned JSON and what is included?

I am creating my first ASP.NET MVC4 Web API. I have a database with 20 or so entities already created and hosted on Azure, and used Entity Framework to reverse engineer the database into POCO classes.

They ended up looking something like this:

public class Activity
{
    public Activity()
    {
        this.ActivityCategories = new List<ActivityCategory>();
        this.ActivityImages = new List<ActivityImage>();
        this.PerformedActivities = new List<PerformedActivity>();
        this.UserActivities = new List<UserActivity>();
    }

    public int ActivityID { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public Nullable<int> Thumbnail { get; set; }
    public virtual Image Image { get; set; }
    public virtual ICollection<ActivityCategory> ActivityCategories { get; set; }
    public virtual ICollection<ActivityImage> ActivityImages { get; set; }
    public virtual ICollection<PerformedActivity> PerformedActivities { get; set; }
    public virtual ICollection<UserActivity> UserActivities { get; set; }
}

Then, I created an ApiController extension class with an action like so:

    public IEnumerable<Activity> All()
    {
        return db.Activities.ToArray();
    }

And, as expected, it returned a very long JSON reply. The JSON reply included everything defined in the Activity class. But what if I don't want to include EVERYTHING? For instance, I don't want to return things like UserActivities, PerformedActivities, etc.

Basically I want my JSON to look something like:

[
    {
        "id":"32",
        "name":"this activity name",
        "description":"blah blah",
        "thumbnail":"http://mydomain.com/images/32/thumbnail.png",
        "images": [
            {
                "name":"this image",
                "url":"http://mydomain.com/images/32/1.png",
            },
            {
                "name":"cool image",
                "url":"http://mydomain.com/images/32/2.png",
            },
        ],
    },
    ...
]

(ignore any formatting errors in my JSON, just typed up the example really fast)

Notice, I don't want to necessarily use the same property names either. Is there an efficient way to massage my data into the format I want?

My first thought is to copy each activity into an array of structs that only include the properties I want. Is there a more elegant solution?

DTO object would rescue you in this case, DTO will provide enough data for your consumer, so define DTO with which data need to be transfer thru Web API. In some cases, you can use your Model from your EF, but:

  1. Normally, EF will generate dynamic proxy under the hood to support lazy loading and tracking changes. The issue you might get is serialization problem, because Web API will serialize proxies, not your POCO object.

  2. Transferring too much needless data to consumer will make HTTP request kind of heavy and disclose the data leak.

  3. Violate separation of concerns, when EF Model is domain entities, they do not take responsibility as data transfer object.

In your sample, you can define ActivityDto , and eliminate needless properties as you mentioned:

public class ActivityDto
{
    public string Name { get; set; }
    public string Description { get; set; }
    public Nullable<int> Thumbnail { get; set; }
    public virtual Image Image { get; set; }
}

public IEnumerable<Activity> All()
{
    return db.Activities.Select(a => new ActivityDto(){
        Name = a.Name,
        Description = a.Description,
        Thumbnail = a.Thumbnail
        // More properties if you need

    }).ToArray();
}

In case you want to look for a tool to map DTO to EF Model automatically, AutoMapper is here.

In MVC it's not really best practice to use a database entity as a model, instead I'd create a POCO (or even more complex object) as your ViewModel than you can then return that only contains the data that is needed by your view (or in this case API user). If you just want to manipulate the data returned, I'm not sure how to do that, but I know WebAPI uses newtonsoft's JSON.NET library to output JSON so you would look into the ways to manipulate that.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM