为什么当我调用CreateItemAsync时,Cosmos DB给我一个“输入名称'{'无效”的错误

时间:2019-11-06 20:10:53

标签: asp.net-core azure-cosmosdb azure-cosmosdb-sqlapi

我正在使用Azure Cosmos DB作为持久性存储的ASP.Net Core 3.0 API。这是我第一次使用Cosmos DB。当我尝试创建新项目(文档)时,我收到了邮递员中的错误消息,提示...

"Response status code does not indicate success: 400 Substatus: 0 
Reason: (Message: {\"Errors\":[\"The input name '{' is invalid. 
Ensure to provide a unique non-empty string less than '1024' characters."

我不知道是什么原因引起的。

我在我的项目中使用Microsoft.Azure.Cosmos v3.4.0 nuget

这是我的存储库中用于添加新帐户文档的方法。

public async Task AddAccountAsync(Account account)
{
    await _container.CreateItemAsync(account, new PartitionKey(account.Id));
}

在调试模式下,当我将鼠标悬停在“ Account account”对象上时,这里是属性值的图片。

enter image description here

我在Cosmos DB中的容器设置为/ id作为分区键。

这是我在邮递员中的请求正文;

{
  "id": "00000000-0000-0000-0000-000000000000",
  "accountName": "Test Company 1",
  "accountType": 1,
  "ownerId": "00000000-0000-0000-0000-000000000000",
  "isTaxExempt": false,
  "mailJobProxyId": "00000000-0000-0000-0000-000000000000",
  "salesPersonId": "00000000-0000-0000-0000-000000000000"

}

这是Account类;

public class Account
{

    // Aggregate state properties
    [JsonProperty(PropertyName = "id")]
    public AccountId Id { get; set; }

    [JsonProperty(PropertyName = "accountName")]
    public AccountName AccountName { get; set; }

    [JsonProperty(PropertyName = "accountType")]
    public AccountTypes AccountType { get; set; }

    [JsonProperty(PropertyName = "ownerId")]
    public OwnerId OwnerId { get; set; }

    [JsonProperty(PropertyName = "isTaxExempt")]
    public bool IsTaxExempt { get; set; }

    [JsonProperty(PropertyName = "mailJobProxyId")]
    public MailJobProxyId MailJobProxyId { get; set; }

    [JsonProperty(PropertyName = "salesPersonId")]
    public SalesPersonId SalesPersonId { get; set; }

    [JsonProperty(PropertyName = "addresses")]
    public List<Address.Address> Addresses { get; set; }

    [JsonProperty(PropertyName = "contacts")]
    public List<Contact.Contact> Contacts { get; set; }

    [JsonProperty(PropertyName = "postagePaymentMethods")]
    public List<PostagePaymentMethod.PostagePaymentMethod> PostagePaymentMethods { get; set; }

    public Account(string id, string accountName, AccountTypes accountType, string ownerId, Guid mailJobProxyId, Guid salesPersonId, bool isTaxExempt)
    {
        Id = AccountId.FromString(id);
        AccountName = AccountName.FromString(accountName);
        AccountType = accountType;
        OwnerId = OwnerId.FromString(ownerId);
        MailJobProxyId = new MailJobProxyId(mailJobProxyId);
        SalesPersonId = new SalesPersonId(salesPersonId);
        IsTaxExempt = isTaxExempt;
        Addresses = new List<Address.Address>();
        Contacts = new List<Contact.Contact>();
        PostagePaymentMethods = new List<PostagePaymentMethod.PostagePaymentMethod>();
        Status = Status.Active;

    }
}

如果您需要其他代码示例,请告诉我。

在美国东部标准时间6:43p更新11/6/19

这是AccountId值对象

   public class AccountId : Value<AccountId>
    {
        public string Value { get; internal set; }

        // Parameterless constructor for serialization requirements
        protected AccountId() { }

        internal AccountId(string value) => Value = value;

        // Factory pattern
        public static AccountId FromString(string accountId)
        {
            CheckValidity(accountId);
            return new AccountId(accountId);
        }

        public static implicit operator string(AccountId accountId) => accountId.Value;

        private static void CheckValidity(string value)
        {
            if (!Guid.TryParse(value, out _))
            {
                throw new ArgumentException(nameof(value), "Account Id is not a GUID.");
            }
        }
    }

这是Startup.cs中的初始化类,用于设置数据库和容器。

private static async Task<AccountsRepository> InitializeCosmosClientAccountInstanceAsync(IConfigurationSection configurationSection)
{
    var databaseName = configurationSection.GetSection("DatabaseName").Value;
    string uri = configurationSection.GetSection("Uri").Value;
    string key = configurationSection.GetSection("Key").Value;
    CosmosClientBuilder clientBuilder = new CosmosClientBuilder(uri, key);
    CosmosClient client = clientBuilder
                        .WithConnectionModeDirect()
                        .Build();
    DatabaseResponse database = await client.CreateDatabaseIfNotExistsAsync(databaseName);

    string containerName = configurationSection.GetSection("AccountsContainerName").Value;
    await database.Database.CreateContainerIfNotExistsAsync(containerName, "/id");
    AccountsRepository cosmosDbService = new AccountsRepository(client, databaseName, containerName);

    return cosmosDbService;
} 

这是发生错误时的堆栈跟踪;

stackTrace": "   at Microsoft.Azure.Cosmos.ResponseMessage.EnsureSuccessStatusCode()\r\n
at Microsoft.Azure.Cosmos.CosmosResponseFactory.ToObjectInternal[T]
(ResponseMessage cosmosResponseMessage, CosmosSerializer jsonSerializer)\r\n
at Microsoft.Azure.Cosmos.CosmosResponseFactory. 
<CreateItemResponseAsync>b__6_0[T](ResponseMessage cosmosResponseMessage)\r\n
at Microsoft.Azure.Cosmos.CosmosResponseFactory.ProcessMessageAsync[T]
(Task`1 cosmosResponseTask, Func`2 createResponse)\r\n   at
Delivery.Api.Infrastructure.AccountsRepository.AddAccountAsync(Account
account) in 
C:\\AzureDevOps\\Delivery\\Delivery.Api\\Accounts\\AccountsRepository.cs:line 20\r\n 
at Delivery.Api.Accounts.AccountsApplicationService.HandleCreate(Create cmd) 
in C:\\AzureDevOps\\Delivery\\Delivery.Api\\Accounts\\AccountsApplicationService.cs:line 43\r\n 
at Delivery.Api.Infrastructure.RequestHandler.HandleCommand[T](T request, Func`2 handler, ILogger log) 
in C:\\AzureDevOps\\Delivery\\Delivery.Api\\Infrastructure\\RequestHandler.cs:line 16

1 个答案:

答案 0 :(得分:2)

您可能需要为AccountIdOwnerId等创建自定义转换器。

这是我的考试:

AccountIdConverter类

    class AccountIdConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return (objectType == typeof(AccountId));
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            return AccountId.FromString(JToken.Load(reader).ToString());
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            JToken.FromObject(value.ToString()).WriteTo(writer);
        }
    }

类AccountId

添加toString方法,并设置为使用自定义转换器

    [JsonConverter(typeof(AccountIdConverter))]
    public class AccountId
    {
        public string Value { get; internal set; }
        protected AccountId() { }

        internal AccountId(string value) => Value = value;

        public static AccountId FromString(string accountId)
        {
            CheckValidity(accountId);
            return new AccountId(accountId);
        }

        public static implicit operator string(AccountId accountId) => accountId.Value;

        public override string ToString()
        {
            return Value;
        }
        private static void CheckValidity(string value)
        {
            if (!Guid.TryParse(value, out _))
            {
                throw new ArgumentException(nameof(value), "Account Id is not a GUID.");
            }
        }
    }

班级帐户

    class Account
    {
        [JsonProperty(PropertyName = "id")]
        public AccountId Id { get; set; }

        public Account(string id)
        {
            Id = AccountId.FromString(id);
        }
    }

测试

    static void Main(string[] args)
    {
        // Test toString 
        AccountId accountId = AccountId.FromString(Guid.NewGuid().ToString());
        Console.WriteLine(accountId.ToString());

        // Test AccountIdConverter
        Console.WriteLine(JsonConvert.SerializeObject(accountId));

        // Test for serializing Account
        Account account = new Account(Guid.NewGuid().ToString());
        string accountJson = JsonConvert.SerializeObject(account);
        Console.WriteLine(accountJson);

        // Test for deserializing Account
        Account accountDeserialized = JsonConvert.DeserializeObject<Account>(accountJson);
        Console.WriteLine(accountDeserialized.Id);

        Console.ReadLine();
    }

结果

enter image description here

您会看到包含Account对象的AccountId对象可以按预期正确进行序列化和反序列化。