满足.NET SDK Newtonsoft.Json.JsonReaderException正在将JSON反序列化为PO



更新1 8.2020年7月:也许我不应该从富文本字段类型开始,这似乎需要相当多的额外工作才能访问:

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

更新2020年7月9日:难怪它不能将Rich Text序列化为字符串。看看它是如何存储富文本的:

"字段":{"richTextField":{"nodeType":"文档";,"数据":{},"内容":[{"nodeType":"段落";,"内容":[{"nodeType":"文本";,"值":"这是";,"标记":[],"数据":{}},{"nodeType":"文本";,"值":"富文本";,"标记":[{"类型":"下划线";}],"数据":{}},{"nodeType":"文本";,"值":"字段&";,"标记":[],"数据":{}}],"数据":{}}]},

将其重新组装到HTML中看起来并不有趣。如果我想把它分解,我会使用HtmlAgilityPack。

更新3 2020年7月9日:

事实上,这没有任何意义。此文档建议我的模型在POCO中使用这个Contentful Document类,并且它们应该包含用于访问数据的其他Contentful特定代码。

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

我不知道怎么会有人使用这个系统。请纠正我的误解。

原始线程

我在上发布了这个https://www.contentfulcommunity.com/,但我不知道如何通过主持人获得该帖子。

我试着按照这些指示进行"满足"。NET SDK访问条目:

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

我可能正在使用更新的。NET核心,但它不是这样编译的。这编译:

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:tempcfcltCfCltContentful.CoreContentfulClient.cs:line 136
at CfClt.Program.Main(String[] args) in c:tempcfcltCfCltCfCltProgram.cs:line 26
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,在这种情况下,这将返回其中一个,但其他线程是否可能覆盖结果后缀,在该方法已经返回数据后更改返回给调用方的数据?也许我需要显式地创建线程,并在第一次匹配时取消这些线程。

相关内容

  • 没有找到相关文章

最新更新