ASP.NET MVC4 Web API - 控制返回的JSON的格式以及包含的内容?

时间:2012-09-18 17:09:59

标签: c# asp.net json asp.net-mvc-4 asp.net-web-api

我正在创建我的第一个ASP.NET MVC4 Web API。我有一个数据库,已经在Azure上创建并托管了20个左右的实体,并使用Entity Framework将数据库反向工程为POCO类。

他们最终看起来像这样:

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

然后,我创建了一个ApiController扩展类,其动作如下:

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

而且,正如预期的那样,它返回了一个非常长的JSON回复。 JSON回复包含Activity类中定义的所有内容。但是,如果我不想包括所有内容呢?例如,我不想返回UserActivities,PerformedActivities等内容。

基本上我希望我的JSON看起来像:

[
    {
        "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",
            },
        ],
    },
    ...
]

(忽略我的JSON中的任何格式错误,只是快速输入示例)

注意,我不一定要使用相同的属性名称。有没有一种有效的方法将我的数据按到我想要的格式?

我的第一个想法是将每个活动复制到仅包含我想要的属性的结构数组中。有更优雅的解决方案吗?

2 个答案:

答案 0 :(得分:4)

在这种情况下,DTO对象会拯救你,DTO将为你的消费者提供足够的数据,所以定义DTO需要通过Web API传输哪些数据。在某些情况下,您可以使用EF中的模型,但是:

  1. 通常情况下,EF会在引擎盖下生成动态代理,以支持延迟加载和跟踪更改。您可能遇到的问题是序列化问题,因为Web API将序列化代理,而不是您的POCO对象。

  2. 将过多的不必要数据传输给消费者会使HTTP请求变得沉重并泄露数据泄漏。

  3. 违反关注点分离,当EF模型是域实体时,他们不承担数据传输对象的责任。

  4. 在您的示例中,您可以定义ActivityDto,并消除您提到的不必要的属性:

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

    如果您想要查找自动将DTO映射到EF模型的工具,AutoMapper就在这里。

答案 1 :(得分:1)

在MVC中,将数据库实体用作模型并不是最佳实践,而是创建一个POCO(甚至更复杂的对象)作为ViewModel,然后返回它只包含所需的数据您的视图(或者在这种情况下是API用户)。如果你只是想操纵返回的数据,我不知道该怎么做,但我知道WebAPI使用newtonsoft的JSON.NET库输出JSON,所以你会研究操纵它的方法。