您当前的位置: 首页 >  缓存

寒冰屋

暂无认证

  • 0浏览

    0关注

    2286博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

使用基于JSON的实体在C#中缓存远程数据

寒冰屋 发布时间:2019-12-08 21:20:46 ,浏览量:0

 

  • 从GitHub下载最新消息
介绍

除了查询基于JSON / REST的远程服务的简洁方法之外,您通常还需要一种方法来缓存和索引您获取的数据。这对于Web服务尤为重要,因为它们的性质,以及连接服务的延迟+无状态,更不用说请求限制,它们往往会返回“大块”数据——即大块数据。在这种情况下,基于JSON的系统通常会在单个查询中返回多个嵌套的数据级联。正确有效地处理这个问题有几个复杂问题,其中一些我们将在本文中讨论。

了解混乱

我将展示REST调用URL以及在我们浏览时打印出来的结果。我们来看一下展示的数据吧。正如我所说,它很大。

以下是来自themoviedb.org的API的“Burn Notice”的电视节目信息:

“invoke:” https://api.themoviedb.org/3/tv/2919?api_key=c83a68923b7fe1d18733e8776bba59bb

{
   "id": 2919,
   "backdrop_path": "/lgTB0XOd4UFixecZgwWrsR69AxY.jpg",
   "created_by": [
         {
            "id": 1233032,
            "credit_id": "525749f819c29531db09b231",
            "name": "Matt Nix",
            "gender": 2,
            "profile_path": "/qvfbD7kc7nU3RklhFZDx9owIyrY.jpg"
         }
      ],
   "episode_run_time": [
         45
      ],
   "first_air_date": "2007-06-28",
   "genres": [
         {
            "id": 10759,
            "name": "Action & Adventure"
         },
         {
            "id": 18,
            "name": "Drama"
         }
      ],
   "homepage": "http://usanetwork.com/burnnotice",
   "in_production": false,
   "languages": [
         "en"
      ],
   ...

就这样继续下去。查看节点,例如created_by——它们是子对象。再往下(这里省略),有完整的数据!(如果单击我提供的链接,您将获得所有这些。)

这里要说的是你需要一种方法来存储这些数据并保留层次结构。它已经是JSON了, 所以如果你把它保存在JSON格式的某种表示中,那么你的工作就会更深入。

这可能看起来不那么糟糕,但是当它包含重叠数据时,这种大数据变得更加困难。 例如,我可能已经执行了查询以获得上面的结果,然后我想获得TMDb关于created_by字段的人“Matt Nix”的所有信息。好吧,我可以这么做,但我不一定非得这么做,因为正如你所见,有些信息已经在里面了:

{
   "id": 1233032,
   "credit_id": "525749f819c29531db09b231",
   "name": "Matt Nix",
   "gender": 2,
   "profile_path": "/qvfbD7kc7nU3RklhFZDx9owIyrY.jpg"
}

这是一个相当多的信息。也许这就是我们需要的一切,也许不是。如果我想要他的IMDb ID怎么办?如果我想要他的生日怎么办?我们必须去服务器。所以我们提出另一个请求,使用上面的id

...

“invoke:”https://api.themoviedb.org/3/person/1233032?api_key=c83a68923b7fe1d18733e8776bba59bb

{
   "id": 1233032,
   "credit_id": "525749f819c29531db09b231",
   "name": "Matt Nix",
   "gender": 2,
   "profile_path": "/qvfbD7kc7nU3RklhFZDx9owIyrY.jpg",
   "birthday": "1971-09-04",
   "known_for_department": "Writing",
   "also_known_as": [],
   "biography": "",
   "popularity": 0.742,
   "adult": false,
   "imdb_id": "nm0633180"
}

这是相同的数据,只是其中包含更多数据。这是在线可查询JSON存储库的典型模式。这很好,只是,我们现在用它做什么?好吧,我们显然希望将它与我们在创建的字段中已有的数据合并,对吧?嗯,类似的东西,但没有。我们稍后会介绍。不管怎样,结果是一样的,但我们会很聪明的。但基本上,我们需要能够最终存储并查询这些信息,因此我们不必每次都返回服务器,并且我们需要一种智能地推迟到服务器的方法,直到我们真正需要我们想要的数据。换句话说,如果我们已经缓存了一些数据,我们不希望再次访问服务器,但如果我们不这样做,我们需要透明地获取它,并按需将其放入缓存中。

显然,第二个问题是远程和本地解决。我们怎么知道使用上面的“id”来运行第二个查询?我们如何确切地知道在本地存储库中存储信息的位置,以便我们以后可以快速获取?

所以基本上,我们必须面对存储和寻址的问题。我提出了一个简单的解决方案,使用JSON本身来完成大部分繁重的工作。

我将再一次重新审视我在这里发布的TMDb和Json代码库,其中的链接位于顶部。

编码这个混乱 存储此混乱

提到的第一个问题是存储,所以我们将从那里开始。我们用IDictionary来保存我们的JSON {}对象。这样做的原因是我们有索引来加快查找速度。与此同时,我们必须为我们的值使用object,因为它们可以是映射到JSON的任意类型之一——JSON []数组的IList,映射到JSON的数值类型,当然还有string,bool和null。

我们使用包含雄心勃勃命名为“Json”的库来将JSON文本转换为此文本并返回,并支持对其进行查询。我们还将使用它来执行远程RPC / REST调用(在本例中为TMDb)。所有那些繁重的小包装。如果你愿意,你可以用NewtonSoft的产品或其他东西转换它,但要小心,因为我已经围绕字典类编排了这个。如果第三方不使用这些,你的工作就会变得更加困难。

首先,我们需要一个字典来查找我们的所有数据的根。我们所有的实体都会在这个下面的某个地方使用词典。除非你想为你的实体搞乱一个构造函数,并且代码很复杂,否则你需要保持一些静态状态。因此,每个实体都需要知道如何找到根,我们使用的机制涉及保持静态。这不是线程安全的,所以我们所做的就是使用static ThreadLocal 保存我们的数据。这意味着数据基于每个线程。这样做有好处,比如不需要锁定,并增加了简单性,以及缓存未命中(我们会达到此目的)和增加多线程应用程序中的内存使用量等缺点,因为您必须为每个线程保留一个数据存储。如果您使用某种二级缓存机制(如此这个小Json 库),那么前面的缓存丢失问题就会得到缓解。后一个内存使用问题在ASP.NET Web服务器环境中得到缓解,因为页面运行时很短并且保持活动连接往往在请求相同的线程请求上提供,这意味着您通常可以从以前的请求访问缓存,而不是在每个请求上创建一个新的缓存。

public static class Tmdb
{
    const string _apiUrlBase = "https://api.themoviedb.org/3";
    static ThreadLocal 
           _json=new ThreadLocal(()=>new JsonObject());
    public static IDictionary Json { get { return _json.Value; } }
    public static string ApiKey { get; set; }
    public static string Language { get; set; }
}

上面的JsonObject只是我们的“Json”库提供的一个薄包装器,它包装了一个Dictionary 类。它并没有什么特别之处,尽管它具有标准字典不共享的特性,如值语义。我们不在这里使用它们。你可以把它变成你想要的Dictionary。

你会注意到除了这个static ThreadLocal

关注
打赏
1665926880
查看更多评论
立即登录/注册

微信扫码登录

0.0492s