为什么 Cosmos DB 在我调用 CreateItemAsync 时给我一个 "The input name '{' is invalid" 错误
Why is Cosmos DB giving me an "The input name '{' is invalid" error when I call CreateItemAsync
我正在使用 Azure Cosmos DB 作为持久性存储的 ASP.Net Core 3.0 API。这是我第一次尝试使用 Cosmos DB。当我尝试创建新项目(文档)时,我在 Postman 中收到一条错误消息,内容为...
"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" 对象上时 属性 值的图片。
我在 Cosmos DB 中的容器设置为 /id 作为分区键。
这是我在 Postman 中的请求正文;
{
"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"
}
这是帐户 class;
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;
}
}
如果您需要其他代码示例,请告诉我。
更新 2019 年 11 月 6 日 6:43p EST
这里是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 中设置数据库和容器的初始化 class。
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
您可能需要为 AccountId
、OwnerId
等创建自定义转换器。
这是我的测试:
class 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);
}
}
class 账号
添加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 账户
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();
}
结果
可以看到包含AccountId
对象的Account
对象可以正常序列化和反序列化。
我正在使用 Azure Cosmos DB 作为持久性存储的 ASP.Net Core 3.0 API。这是我第一次尝试使用 Cosmos DB。当我尝试创建新项目(文档)时,我在 Postman 中收到一条错误消息,内容为...
"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" 对象上时 属性 值的图片。
我在 Cosmos DB 中的容器设置为 /id 作为分区键。
这是我在 Postman 中的请求正文;
{
"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"
}
这是帐户 class;
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;
}
}
如果您需要其他代码示例,请告诉我。
更新 2019 年 11 月 6 日 6:43p EST
这里是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 中设置数据库和容器的初始化 class。
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
您可能需要为 AccountId
、OwnerId
等创建自定义转换器。
这是我的测试:
class 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);
}
}
class 账号
添加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 账户
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();
}
结果
可以看到包含AccountId
对象的Account
对象可以正常序列化和反序列化。