0

更新 1 8.July.2020:也许我不应该从富文本字段类型开始,这似乎需要做很多额外的工作才能访问:

https://www.contentful.com/developers/docs/net/tutorials/rich-text/

更新 2 9.July.2020:难怪它不能将富文本序列化为字符串。看看它是如何存储富文本的:

“字段”:{“richTextField”:{“节点类型”:“文档”,“数据”:{},“内容”:[{“节点类型”:“段落”,“内容”:[{“节点类型”:“ text", "value": "这是", "marks": [], "data": {} }, { "nodeType": "text", "value": "rich text", "marks": [ { "type": "underline" } ], "data": {} }, { "nodeType": "text", "value": "field.", "marks": [], "data": { } } ], “数据”: {} } ] },

重新组装成 HTML 看起来并不有趣。如果我想让它分解,我会使用 HtmlAgilityPack。

2020 年 7 月 9 日更新 3:

实际上,这没有任何意义。该文档建议我的模型在我的 POCO 中使用这个 Contentful Document 类,并且它们应该包含额外的 Contentful-specific 代码来访问数据。

无头 CMS 的主要目标之一是避免供应商特定的 API(锁定)。有效的方式是 CMS 只是水合 POCO,基本上是从 JSON 反序列化。没有其他无头 CMS 会从富文本填充这样的结构,因此仅使用这种疯狂的 HTML 格式会导致供应商锁定或需要进行重大代码大修来更改 CMS(不仅仅是更改 POCO水合逻辑,但改变 POCO 本身)。更不用说像这样构建 HTML 对 JSON 负载和 CPU 负载的影响了。无论如何,对于富文本字段(可能是 CMS 中最常见的元素之一)的内容架构,有一堆特定于供应商的编码只是为了获得价值,而前端变得太清楚了CMS。所以我必须反序列化为某种中间对象,然后使用它们来填充我的视图模型。或者我可以将围绕 Document 的所有逻辑复制到我自己的项目中,但这听起来几乎更糟。

我看不出任何人如何使用这个系统。请纠正我的误解。

原始线程

我在https://www.contentfulcommunity.com/上发布了这篇文章,但我不知道如何通过版主获取该帖子。

我尝试按照 Contentful .NET SDK 的这些说明来访问条目:

https://github.com/contentful/contentful.net

我可能正在使用较新的 .NET Core,但它不会以这种方式编译。这编译:

using Contentful.Core;
using Contentful.Core.Configuration;
using System;
using System.Net.Http;

namespace CfClt
{
    class Program
    {
        public class Entry
        {
            public string richTextField { get; set; }
        }

        static void Main(string[] args)
        {
            HttpClient httpClient = new HttpClient();
            ContentfulOptions options = new ContentfulOptions
            {
                DeliveryApiKey = "A",
                PreviewApiKey = "B",
                SpaceId = "C"
            };

            ContentfulClient client = new ContentfulClient(httpClient, options);
            Entry entry = client.GetEntry<Entry>("4SVaB1ps4H6Ml9ZxWsCWOn").GetAwaiter().GetResult();
            Console.WriteLine(entry.richTextField);
        }
    }
}

但是我从 JSON 反序列化到 POCO 时遇到异常。这是条目的 JSON:

{
  "sys": {
    "space": {
      "sys": {
        "type": "Link",
        "linkType": "Space",
        "id": "qjiunow8a0ig"
      }
    },
    "id": "4SVaB1ps4H6Ml9ZxWsCWOn",
    "type": "Entry",
    "createdAt": "2020-07-08T19:52:47.34Z",
    "updatedAt": "2020-07-08T19:52:47.34Z",
    "environment": {
      "sys": {
        "id": "master",
        "type": "Link",
        "linkType": "Environment"
      }
    },
    "revision": 1,
    "contentType": {
      "sys": {
        "type": "Link",
        "linkType": "ContentType",
        "id": "firstContentType"
      }
    },
    "locale": "en-US"
  },
  "fields": {
    "richTextField": {
      "nodeType": "document",
      "data": {},
      "content": [
        {
          "nodeType": "paragraph",
          "content": [
            {
              "nodeType": "text",
              "value": "this is the rich text field. What is my ID?",
              "marks": [],
              "data": {}
            }
          ],
          "data": {}
        }
      ]
    }
  }
}

这是一个例外:

Unhandled exception. Newtonsoft.Json.JsonReaderException: Error reading string. Unexpected token: StartObject. Path 'fields.richTextField', line 32, position 22.
   at Newtonsoft.Json.JsonReader.ReadAsString()
   at Newtonsoft.Json.JsonReader.ReadForType(JsonContract contract, Boolean hasConverter)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonSerializer.Deserialize(JsonReader reader, Type objectType)
   at Newtonsoft.Json.Linq.JToken.ToObject(Type objectType, JsonSerializer jsonSerializer)
   at Newtonsoft.Json.Linq.JToken.ToObject[T](JsonSerializer jsonSerializer)
   at Contentful.Core.ContentfulClient.GetEntry[T](String entryId, String queryString, CancellationToken cancellationToken) in C:\temp\cfclt\CfClt\Contentful.Core\ContentfulClient.cs:line 136
   at CfClt.Program.Main(String[] args) in c:\temp\cfclt\CfClt\CfClt\Program.cs:line 26
4

1 回答 1

0
    using Contentful.Core;
    using Contentful.Core.Configuration;
    using Contentful.Core.Models;
    using Deliverystack.Core.Fulcontent.Models.Repositories;
    using System;
    using System.Net.Http;
    
    namespace cfclt
    {
        class Program
        {
            public class Entry
            {
                public string StringField { get; set; }
                public string Url { get; set;  }
                public Document RichTextField { get; set; }
            }
    
            static void Main(string[] args)
            {
                HttpClient httpClient = new HttpClient();
                ContentfulOptions options = new ContentfulOptions
                {
                    DeliveryApiKey = "A",
                    PreviewApiKey = "B",
                    SpaceId = "C"
                };
    
                ContentfulClient client = new ContentfulClient(httpClient, options);
                ContentfulRepository repository = new ContentfulRepository(client);
                Entry entry = repository.Get<Entry>("/");
                Console.WriteLine(entry + " : " + entry.StringField + " : " + entry.Url + " : " + new HtmlRenderer().ToHtml(entry.RichTextField).GetAwaiter().GetResult());
            }
        }
    }
    
using Contentful.Core;
using Contentful.Core.Models;
using Contentful.Core.Search;
using Deliverystack.Core.Models.Repositories;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Deliverystack.Core.Fulcontent.Models.Repositories
{
    public class ContentfulRepository : IRepository
    {
        private ContentfulClient _client;

        public ContentfulRepository(ContentfulClient client)
        {
            _client = client;
        }

        public override TEntryModel Get<TEntryModel>(string entryIdentifier, string contentTypeUid = null)
        {
            TEntryModel result = null;

            if (!entryIdentifier.StartsWith("/"))
            {
                result = _client.GetEntry<TEntryModel>(entryIdentifier).GetAwaiter().GetResult();
            }
            else
            {
                List<string> contentTypes = new List<string>();

                if (contentTypeUid != null)
                {
                    contentTypes.Add(contentTypeUid);
                }
                else
                {
                    foreach (ContentType doNotUseCt in _client.GetContentTypes().GetAwaiter().GetResult())
                    {
                        ContentType myContentType = doNotUseCt;
                        contentTypes.Add(myContentType.SystemProperties.Id);
                    }
                }

                foreach(string doNotUseCti in contentTypes)
                { 
                    string myContentTypeUid = doNotUseCti;
                    QueryBuilder<TEntryModel> queryBuilder = QueryBuilder<TEntryModel>.New.ContentTypeIs(myContentTypeUid).FieldEquals("fields.url", entryIdentifier);
                    ContentfulCollection<TEntryModel> entries = _client.GetEntries(queryBuilder).GetAwaiter().GetResult();

                    if (entries.Count() > 0)
                    {
                        result = entries.Items.First();
                    }
                }
            }

            return result;
        }

实际上这有点不确定,因为多个内容类型中的多个条目可能有一个共同的 URL,在这种情况下,这将返回其中一个,但那些其他线程可能会覆盖结果后缀,在此之后更改返回给调用者的数据方法已经返回了该数据?也许我需要明确创建线程并在第一次匹配时取消这些线程。

于 2020-07-09T13:22:59.630 回答