首页 > 解决方案 > Microsoft.Azure.Cosmos.Container.ReadItemAsync() 失败 - json 解析 - 意外字符

问题描述

我正在将一些 C# 代码从 Microsoft.Azure.Documents 移植到 Microsoft.Azure.Cosmos。我创建了一个小测试用例,试图让它在使用我的完整应用程序测试它之前访问 CosmosDB。我将在下面进一步添加我的完整代码,但这是我认为相关的内容。

try {
   Container container = client.GetContainer(DocumentDBDatabaseName, collectionId);
   RequestOptions requestOptions = new RequestOptions();
   ThroughputProperties tputprops = await container.ReadThroughputAsync(requestOptions);
   Console.WriteLine($"Throughput: {tputprops.Throughput}");
   ContainerProperties containerProperties = await container.ReadContainerAsync();
   Console.WriteLine($"Container props: {containerProperties}");
   // We don't use any partition keys, so use PartitionKey.None
   ItemRequestOptions iro = new ItemRequestOptions();
   ItemResponse<string> result = await container.ReadItemAsync<string>(documentDBStorageId, PartitionKey.None, iro);
   return result;  // successful return
} catch (CosmosException exc) {
   Console.WriteLine("{0} error occurred: {1}", exc.StatusCode, exc);
} catch (Exception exc) {
   Console.WriteLine("Error: {0}", exc);
}

输出如下所示:

吞吐量:400
容器道具:Microsoft.Azure.Cosmos.ContainerProperties
错误:Newtonsoft.Json.JsonReaderException:解析值时遇到意外字符:{。路径'',第 1 行,位置 1。
   在 Newtonsoft.Json.JsonTextReader.ReadStringValue(ReadType readType)
   在 Newtonsoft.Json.JsonTextReader.ReadAsString()
   在 Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ReadForType(JsonReader reader, JsonContract contract, Boolean hasConverter)
   在 Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader 阅读器,类型 objectType,布尔 checkAdditionalContent)
   在 Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader 阅读器,类型 objectType)
   在 Newtonsoft.Json.JsonSerializer.Deserialize[T](JsonReader 阅读器)
   在 Microsoft.Azure.Cosmos.CosmosJsonDotNetSerializer.FromStream[T](流流)
   在 Microsoft.Azure.Cosmos.CosmosJsonSerializerWrapper.FromStream[T](流流)
   在 Microsoft.Azure.Cosmos.CosmosSerializerCore.FromStream[T](流流)
   在 Microsoft.Azure.Cosmos.CosmosResponseFactoryCore.ToObjectpublic[T](ResponseMessage responseMessage)
   在 Microsoft.Azure.Cosmos.CosmosResponseFactoryCore.b__8_0[T](ResponseMessage cosmosResponseMessage)
   在 Microsoft.Azure.Cosmos.CosmosResponseFactoryCore.ProcessMessage[T](ResponseMessage responseMessage, Func`2 createResponse)
   在 Microsoft.Azure.Cosmos.CosmosResponseFactoryCore.CreateItemResponse[T](ResponseMessage responseMessage)
   在 Microsoft.Azure.Cosmos.ContainerCore.d__56`1.MoveNext()
--- 从先前抛出异常的位置结束堆栈跟踪 ---
   在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务任务)
   在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务)
   在 Microsoft.Azure.Cosmos.ClientContextCore.d__38`1.MoveNext()
--- 从先前抛出异常的位置结束堆栈跟踪 ---
   在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务任务)
   在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务)
   在 System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   在 C:\Users\buchs\Work-NCS\TestCosmos2\TestCosmos\Program.cs:line 46 中的 TestCosmos_ns.TestCosmos_cl.d__3.MoveNext()

documentDBstorageid 只是一个与数据库中找到的文档 ID 匹配的字符串。数据库不使用分区键。显然容器很好,因为我可以毫无例外地从中收集其他数据。

这是更完整的代码

// Package: Microsoft.Azure.Cosmos --version 3.12.0
using System;
using System.Threading.Tasks;
using Microsoft.Azure.Cosmos;

namespace TestCosmos_ns
{
    class TestCosmos_cl
    {
        private static string DocumentDBDatabaseName = "mydbname";
        public static void Main(string[] args)
        {
            Task Ta = AsyncMain(args);
            Ta.Wait();  // Wait for all async tasks to close.
        }

        public static async Task AsyncMain(string[] args)
        {
            // corresponds to CosmosDB container
            string EmployeeCollection = "directory";
            string docId2 = GetDocumentDBStorageId("company", "companyid", "locationx");
            string u = await GetDocumentById(EmployeeCollection, docId2);
            Console.WriteLine("GetDocumentById returns:");
            Console.WriteLine(u);
            bool v = DocumentExists(EmployeeCollection, docId2);
            Console.WriteLine("DocumentExists() returns:");
            Console.WriteLine(v);
        }
        public static async Task<string> GetDocumentById(string collectionId, string documentDBStorageId)
        {
            CosmosClient client = GetDocumentDBClient();
            try {
                Container container = client.GetContainer(DocumentDBDatabaseName, collectionId);
                RequestOptions requestOptions = new RequestOptions();
                ThroughputProperties tputprops = await container.ReadThroughputAsync(requestOptions);
                Console.WriteLine($"Throughput: {tputprops.Throughput}");
                ContainerProperties containerProperties = await container.ReadContainerAsync();
                Console.WriteLine($"Container props: {containerProperties}");
                // We don't use any partition keys, so use PartitionKey.None
                ItemRequestOptions iro = new ItemRequestOptions();
                ItemResponse<string> result = await container.ReadItemAsync<string>(documentDBStorageId, PartitionKey.None, iro);
                return result;  // successful return
            } catch (CosmosException exc) {
                Console.WriteLine("{0} error occurred: {1}", exc.StatusCode, exc);
            } catch (Exception exc) {
                Console.WriteLine("Error: {0}", exc);
            }
            return "";  // return in exception situations
        }

        public static bool DocumentExists(string collectionId, string documentDBStorageId)
        {
            // OK, totally cheating. Just try to retrieve the document, if we get back blank, then there
            // was an exception and it doesn't exist.
            Task<string> getResult = GetDocumentById(collectionId, documentDBStorageId);
            getResult.Wait();
            string result = getResult.Result;
            if (result.Length == 0) {
                return false;
            }
            return true;
        }
        private static CosmosClient TheCosmosClient = null;
        public static CosmosClient GetDocumentDBClient()
        {
            string DocumentDBEndpointUrl = "https://mydb.documents.azure.com:443/";
            string DocumentDBPrimaryKey = "myprimarykey...==";
            TheCosmosClient = TheCosmosClient ?? new CosmosClient(DocumentDBEndpointUrl, DocumentDBPrimaryKey);
            return TheCosmosClient;
        }

        private static string NormalizePath(string result)
        {
            string toReplace = " ,.<>?;:'\"`~!@#$%^&*()-=+";

            foreach (char c in toReplace)
                result = result.Replace(c, '_');

            result = result.Replace("__", "_");
            return result;
        }
        public static string GetDocumentDBStorageId(string companyName, string companyId, string locationName) => NormalizePath($"Employees_{companyName}_{companyId}_{locationName}");
    }
}

标签: c#.netazureazure-cosmosdb

解决方案


请试试这个:

使用此代码:

ItemResponse<JObject> result = await container.ReadItemAsync<JObject>(documentDBStorageId, PartitionKey.None, iro);

代替:

ItemResponse<string> result = await container.ReadItemAsync<string>(documentDBStorageId, PartitionKey.None, iro);

推荐阅读