如果反序列化失败,则跳过 Cosmos DB 容器中的文档

Skip document in Cosmos DB container if the deserialization fails

我有以下代码用于从 Cosmos DB 容器中读取文档:

        var result = new List<StoredLead>();
        var linqSerializerOptions = new CosmosLinqSerializerOptions
        {
            PropertyNamingPolicy = CosmosPropertyNamingPolicy.CamelCase
        };
        var iterator = container.GetItemLinqQueryable<StoredLead>(false, null, null, linqSerializerOptions).Where(expression).ToFeedIterator();

        while (iterator.HasMoreResults)
        {
            var list = await iterator.ReadNextAsync();
            foreach (var lead in list)
            {
                //Do some stuff with the lead
                result.Add(lead);
            }
        }

        return result;

如果 JSON 文档在任何字段中的值不正确(字符串而不是 int,或 int 而不是 date/time),我会得到 Newtonsoft.Json.JsonReaderException,这会导致读取整批对象从要丢弃的容器中。请问是否可以跳过不能反序列化的文档,继续反序列化成功的文档

我尝试使用以下代码创建自定义 CosmosSerializer

public class SerliarizationService : CosmosSerializer
    {
        private readonly JsonSerializer serializer;
        private readonly ILogger _logger;

        public SerliarizationService(ILogger logger)
        {
            _logger = logger;
            serializer = new JsonSerializer
            {
                NullValueHandling = NullValueHandling.Ignore                    
            };
            serializer.Error += HandleError;
        }

        private void HandleError(object sender, Newtonsoft.Json.Serialization.ErrorEventArgs args)
        {
            // only log an error once
            if (args.CurrentObject == args.ErrorContext.OriginalObject)
            {
                _logger.LogError("Error while deserializing document. Error message: {errorMessage}", args.ErrorContext.Error.Message);
                args.ErrorContext.Handled = true;
            }
        }

即当发生反序列化异常时,我尝试记录并抑制错误,但行为并不完全如我所愿。好像给不能成功反序列化的字段设置了默认值,这不是我想要实现的。

以下应该有效:

var iterator = container.GetItemLinqQueryable<StoredLead>()
    .Where(x => x.PartitionKey == "example")
    .Select(x => (object) x)
    .Select(x => (JToken) x)
    .ToFeedIterator();

var results = new List<StoredLead>();
while (iterator.HasMoreResults)
{
    foreach (var item in await iterator.ReadNextAsync())
    {
        try
        {
            results.Add(item.ToObject<StoredLead>());
        }
        catch 
        { 
            //no implementation
        }
    }
}

通过 return 将该项目作为 JToken 您可以对其进行迭代并分别反序列化每个条目。 Select 语句允许您使用强类型的 linq 表达式,但仍然 return 查询结果作为 JToken.