2014-02-20 85 views
5

我正在使用JSON,ASP.NET,typescript/javascript和AngularJS来处理我的Web应用程序设计。
JSON数据结构 - JSON到对象 - 最佳实践

在短: 我需要一个最佳实践为通过JSON从服务器向客户端发送数据,使用在客户端的JSON字符串创建对象。

我有一个WebServerAPI项目(ASP.NET)结构如下:

  • 控制器
    • DataController类(REST API)
  • 型号
    • 类型

模型类:

public class A { 
    public property int Id {get; set;} 
    public property string Name {get; set;} 
    public property Type Type {get; set;} 
} 

public class Type { 
    public property int Id {get; set;} 
    public property string Name {get; set;} 
} 

每个模型类的ID属于数据库中的表(主键)的ID。

的DataController类结构:

public class DataController : ApiController { 
    // ... 
    // GET api/a 
    public IEnumerable<A> Get() 
    { 
     // fetches all As from the database 
     // the facade creates instances of A and Type as required 
     // (if A has a 'Type' the Type will also fetched an set) 
     return facade.GetAll<A>(); 
    } 
    // ... 
} 

的Get()的DataController类的方法返回一个JSON结果。

JSON结果如下所示:

[ 
    {"Id":1, 
    "Type": {"Id":1, "Name":"name1"} 
    }, 
    {"Id":2, 
    "Type": {"Id":2, "Name":"name2"} 
    }, 
    {"Id":3, 
    "Type": {"Id":1, "Name":"name1"} 
    } 
    {"Id":4, 
    "Type": {"Id":2, "Name":"name2"} 
    }, 
    {"Id":5, 
    "Type": {"Id":2, "Name":"name2"} 
    }, 
] 

正如你可以在JSON数据看到一些由于共享同一个类型。虽然这是有效的JSON,但我不知道这是否是发送数据的最佳做法。

那岂不是更好地发送这样的事情:

[ 
    {"Id":1, 
    "TypeId": {"Id":1} 
    }, 
    {"Id":2, 
    "TypeId": {"Id":2} 
    }, 
    {"Id":3, 
    "TypeId": {"Id":1} 
    } 
    {"Id":4, 
    "TypeId": {"Id":2} 
    }, 
    {"Id":5, 
    "TypeId": {"Id":2} 
    }, 
] 

所以我们得到的类型的唯一的ID。但是,我们必须要求所有可用的类型来确定哪个类型必须在相应的As中设置。哪个可能不好?我认为这可能会很慢,因为我必须发送两个查询。

第三个选项可能是在同一个JSON结果中发送所有可用的类型和As。

[ 
    {"Types": 
     [ 
       {"Id":1, "Name":"name1"}, 
       {"Id":2, "Name":"name2"}, 
     ] 
    }, 
    {"As": 
     [ 
      {"Id":1, 
      "TypeId": {"Id":1} 
      }, 
      {"Id":2, 
      "TypeId": {"Id":2} 
      }, 
      {"Id":3, 
      "TypeId": {"Id":1} 
      } 
      {"Id":4, 
      "TypeId": {"Id":2} 
      }, 
      {"Id":5, 
      "TypeId": {"Id":2} 
      } 
     ] 
    } 
] 

所以我想知道是否有最佳做法。反复发送相同的对象(Type)作为A中的嵌套对象似乎相当“愚蠢”。

特别是如果我将JSON字符串转换为Typescript对象。

没有任何“存储/缓存”逻辑创建“相同”的对象一遍又一遍:

export class A { 
    public Id: number; 
    public Name: string; 
    public Type: Type; 

    public static fromData(data: any): A { 

     var a = new A(); 
     a.Id = data.Id; 
     a.Name = data.Name; 
     a.Type = Type.fromData(data.Type); 

     return a; 
    } 
} 

export class Type { 
     public Id: number; 
     public Name: string; 

     public static fromData(data: any) : Type { 
      var type = new Type(); 
      type.Id = data.Id; 
      type.Name = data.Name; 

      return type; 
     } 
} 

// AngularJS controller 
export class AListCtrl { 
    static $inject = ['$scope', '$http']; 

    public As: A[] = []; 

    constructor(private $scope, private $http) { 
     $scope.AListCtrl = this; 

     $http.get('http://localhost/api/a').success((data) => { 
      var as: A[] = []; 
      for (var i = 0; i < data.length; i++) { 
       var aData = data[i]; 
       var a = A.fromData(aData); 

       as.push(a); 
      } 

      this.As = as; 
     }); 
    } 
} 



创建代表同一类型不同的对象似乎只是错误的。因为我在其他语言(C#,Java,C++)中引用了很多东西。使用这种反序列化数据和创建对象的方式,根本不允许使用引用(,也许这在网络应用程序中是错误的?)。而且我也认为,产生大量无用的对象而不是每个类型的对象会浪费内存和CPU时间。

相当长的帖子,但我希望能很好地解释我的问题。

要总结一下:我需要一个最佳实践为通过JSON从服务器向客户端发送数据,使用在客户端的JSON字符串创建对象。

+0

我通常有C#视图模型完全匹配JavaScript视图模型。我发现它使维护更容易,加快了开发时间,将来当我做出改变时,这不是什么大问题(对我来说这比保存几个字节的网络流量更重要)。如果你没有开发一个应用程序,每个字节数或传递大量数据,你不应该担心。在查看新页面时,您已经通过传递json字符串来节省大量字节,而不是重新装入整页。 –

+0

@dhsto不幸的是我必须处理大量的数据(大约1kk对象(As))。但正如你可以在打字稿代码中看到的,我在C#和打字稿中使用了相同的类结构。 – bakunin

回答

3

我认为您需要定义最适合客户端应用程序的JSON表示形式,然后确保以该格式发送数据。我会创建一个自定义序列化器,使用内置的JavaScriptConverter或可能由Json.Net提供的序列化器。只是使用内置的串行器似乎并没有给出理想的结果。

+0

好的,定义我自己的json结构对我来说也是有意义的。你更喜欢哪个选项? 2或3? – bakunin

+0

我会选择3,因为它减少了服务器的往返行程,并且可能(?)稍微简化了您的客户端代码。 –

1

我的个人意见是JSON发送是数据驱动的。从这个意义上讲,它应该独立于客户端,或者你正在使用的数据库结构。例如,如果您检索到一些Foo's,那么JSON应该包含客户端might want to use的所有相关信息,否则您将最终为每个潜在客户端重写您的数据提供API。我倾向于从第三方的角度来看待它;

  • 我是否需要了解有关后备数据库的信息:否。
  • 我希望API能够很轻松地为我提供大量相关信息:是的。

所以总结起来:

[ 
    {"Id":1, 
    "Type": {"Id":1, "Name":"name1"} 
    }, 
    {"Id":2, 
    "Type": {"Id":2, "Name":"name2"} 
    }, 
    {"Id":3, 
    "Type": {"Id":1, "Name":"name1"} 
    } 
    {"Id":4, 
    "Type": {"Id":2, "Name":"name2"} 
    }, 
    {"Id":5, 
    "Type": {"Id":2, "Name":"name2"} 
    }, 
] 

好像你的情况有效。

+0

我经常使用关系数据库,这种表示数据的方式不适合关系数据库的概念。所以这可能是我不喜欢这种数据表示方式的原因:) – bakunin

+1

@bakunin:我可以想象。这绝对是一个不同的思维集。但问问自己这个问题:如果您使用其他人API,您是否真的想要以关系方式查询/合并数据?或者你想要一个漂亮的容器与所有相关的信息?我会选择后者,除非数据量特别大。 – Stefan

+0

@bakunin:另外:也许Type :: Id与客户端不相关。例如,如果类型是只读的,或者不需要通过这种API调用进行编辑。如果不是,可以省略它。 – Stefan

2

在API设计中一个很好的经验法则是制定你的json响应以适应你的客户端需求。我相信一些REST纯粹主义者会不同意,但在现实世界中,减少XHR请求和客户端处理的应用程序优于遵循教条式的资源建模方法。

让您的数据库/服务器端对象模型抽象泄漏到您的客户端将最终花费您的时间和精力。如果您序列化数据以适应您的客户需求,那么即使您的后端实施更改,您也可以保留该接口。

+0

当我想在打字稿中使用引用时,无论如何我都需要映射数据。所以每个Type有1个对象,As引用不同的Type对象。但是也许使用引用是错误的呢? – bakunin

+0

您的客户端模型不一定需要映射到您的服务器端模型。共享模型可以是一个很好的缩时器,但有时候为了性能和可用性对它们进行改变或平坦化是有意义的。 –

+0

@Scoot Puleo:嗯..我同意这一点。我当然可以提供2种获取数据的方法。一个包含选项1中的所有内容,另一个包含我的打字稿/ JavaScript实现,这有助于将数据映射到对象(再次处理引用)。 – bakunin

2

这是一个有趣的问题,我不认为有一个正确的答案,适合所有可能的情况。

一般来说,第三种选择是我首先选择的选项。这是正确的,因为允许您不要复制相同的数据(Type),并且效率很高,因为所有数据都可用于一个请求,这有利于减少XHR请求到服务器的开销。

现在,对于各种情况,其他两个选项都可能有一些优点。例如,如果数据集很小,则可能不希望复制类型数据。

我认为我会记住的是选择适合您的前端代码的最佳表示形式。除非这是您希望与其他客户端共享的通用API,否则我建议将后端和前端良好地协同工作以获得最佳速度,同时让代码在客户端更简单。

希望它有帮助

+0

很好的答案 - 就像其他答案一样,如果我仅将它用于内部API,我似乎应该使用选项3。那么,事实上就是这样,所以我想我会选择3 – bakunin