使用 .NET 在 Angular 和 Cosmos DB 之间传递 "pure"(class-less)json
Passing "pure" (class-less) json between Angular and Cosmos DB with .NET
我在 Cosmos DB 中有 json 数据,我想将其传送到 angular 应用程序。
angular 应用程序可以处理各种 json 结构并允许用户修改数据并推送回 Cosmos(通过 API - 见下文)。
我正在尝试构建一个简单的 C# API,它将仅用于从 Cosmos 查询数据并将“原始”json 推送回 angular,而无需为我正在存储的每种类型的 json 对象创建 classes。 API 只是将数据从 Cosmos 传递到 Angular 并将数据从 Angular.
推回 Cosmos 的机制
我还没有找到一种简单的方法来执行此操作,因为所有方法似乎都需要一个结构化的 class 对象来从 Cosmos 检索数据并将其保存回来。
有什么实现方法的建议吗?
-- 编辑--
这是我在动态中使用的一些示例代码,它在检索数据方面有效,但它不会在中间件中序列化为 Json(请参阅下面的例外情况)。
public async Task<dynamic> GetItemAsync(string id)
{
try
{
var response = await this._container.ReadItemAsync<dynamic>(id, new PartitionKey(id));
return response.Resource;
}
catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
{
return null;
}
}
[15:12:25 ERR] An unhandled exception has occurred while executing the
request.
<s:Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware>
System.NotSupportedException: The collection type
'Newtonsoft.Json.Linq.JObject' is not supported. at
System.Text.Json.JsonPropertyInfoNotNullable`4.GetDictionaryKeyAndValueFromGenericDictionary(WriteStackFrame&
writeStackFrame, String& key, Object& value) at
System.Text.Json.JsonPropertyInfo.GetDictionaryKeyAndValue(WriteStackFrame&
writeStackFrame, String& key, Object& value) at
System.Text.Json.JsonSerializer.HandleDictionary(JsonClassInfo
elementClassInfo, JsonSerializerOptions options, Utf8JsonWriter
writer, WriteStack& state) at
System.Text.Json.JsonSerializer.Write(Utf8JsonWriter writer, Int32
originalWriterDepth, Int32 flushThreshold, JsonSerializerOptions
options, WriteStack& state) at
System.Text.Json.JsonSerializer.WriteAsyncCore(Stream utf8Json, Object
value, Type inputType, JsonSerializerOptions options,
CancellationToken cancellationToken) at
Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext
context, Encoding selectedEncoding) at
Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext
context, Encoding selectedEncoding) at
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Logged|21_0(ResourceInvoker
invoker, IActionResult result) at
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|29_0[TFilter,TFilterAsync](ResourceInvoker
invoker, Task lastTask, State next, Scope scope, Object state, Boolean
isCompleted) at
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed
context) at
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State&
next, Scope& scope, Object& state, Boolean& isCompleted) at
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters()
我还尝试将 System.Text.JSON 与 JSONDocument 一起使用,但在检索数据时它抱怨说它需要一个构造函数作为 class?
的一部分
发生这种情况的原因是因为 Microsoft.Azure.Cosmos
仍然使用 Newtonsoft.Json
进行序列化和反序列化。
您的 ASP.NET 核心应用程序正在使用 System.Text.Json
。在 ASP.NET 核心应用程序中使用 Cosmos 时,我会将解决方案切换为使用 Newtonsoft.Json
而不是 System.Text.Json
。你可以通过添加这个包来做到这一点:
Microsoft.AspNetCore.Mvc.NewtonsoftJson
- 如果您使用的是 .NET Core 3.1,请使用版本
3.1.*
- 如果您使用的是 .NET5,请使用版本
5.0.*
- 如果您使用的是 .NET6,请使用版本
6.0.*
然后,在您的 Startup.cs
中,在 ConfigureServices()
方法中将此更改为:
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddControllers();
// ...
}
为此:
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddControllers().AddNewtonsoftJson();
// ...
}
由于您只想按原样返回对象,请将代码更改为:
public async Task<object> GetItemAsync(string id)
{
try
{
var response = await this._container.ReadItemAsync<object>(id, new PartitionKey(id));
return response.Resource;
}
catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
{
return null;
}
}
不需要使用dynamic
。只需使用 object
.
我在 Cosmos DB 中有 json 数据,我想将其传送到 angular 应用程序。 angular 应用程序可以处理各种 json 结构并允许用户修改数据并推送回 Cosmos(通过 API - 见下文)。
我正在尝试构建一个简单的 C# API,它将仅用于从 Cosmos 查询数据并将“原始”json 推送回 angular,而无需为我正在存储的每种类型的 json 对象创建 classes。 API 只是将数据从 Cosmos 传递到 Angular 并将数据从 Angular.
推回 Cosmos 的机制我还没有找到一种简单的方法来执行此操作,因为所有方法似乎都需要一个结构化的 class 对象来从 Cosmos 检索数据并将其保存回来。
有什么实现方法的建议吗?
-- 编辑--
这是我在动态中使用的一些示例代码,它在检索数据方面有效,但它不会在中间件中序列化为 Json(请参阅下面的例外情况)。
public async Task<dynamic> GetItemAsync(string id)
{
try
{
var response = await this._container.ReadItemAsync<dynamic>(id, new PartitionKey(id));
return response.Resource;
}
catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
{
return null;
}
}
[15:12:25 ERR] An unhandled exception has occurred while executing the request. <s:Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware> System.NotSupportedException: The collection type 'Newtonsoft.Json.Linq.JObject' is not supported. at System.Text.Json.JsonPropertyInfoNotNullable`4.GetDictionaryKeyAndValueFromGenericDictionary(WriteStackFrame& writeStackFrame, String& key, Object& value) at System.Text.Json.JsonPropertyInfo.GetDictionaryKeyAndValue(WriteStackFrame& writeStackFrame, String& key, Object& value) at System.Text.Json.JsonSerializer.HandleDictionary(JsonClassInfo elementClassInfo, JsonSerializerOptions options, Utf8JsonWriter writer, WriteStack& state) at System.Text.Json.JsonSerializer.Write(Utf8JsonWriter writer, Int32 originalWriterDepth, Int32 flushThreshold, JsonSerializerOptions options, WriteStack& state) at System.Text.Json.JsonSerializer.WriteAsyncCore(Stream utf8Json, Object value, Type inputType, JsonSerializerOptions options, CancellationToken cancellationToken) at Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding) at Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Logged|21_0(ResourceInvoker invoker, IActionResult result) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|29_0[TFilter,TFilterAsync](ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters()
我还尝试将 System.Text.JSON 与 JSONDocument 一起使用,但在检索数据时它抱怨说它需要一个构造函数作为 class?
的一部分发生这种情况的原因是因为 Microsoft.Azure.Cosmos
仍然使用 Newtonsoft.Json
进行序列化和反序列化。
您的 ASP.NET 核心应用程序正在使用 System.Text.Json
。在 ASP.NET 核心应用程序中使用 Cosmos 时,我会将解决方案切换为使用 Newtonsoft.Json
而不是 System.Text.Json
。你可以通过添加这个包来做到这一点:
Microsoft.AspNetCore.Mvc.NewtonsoftJson
- 如果您使用的是 .NET Core 3.1,请使用版本
3.1.*
- 如果您使用的是 .NET5,请使用版本
5.0.*
- 如果您使用的是 .NET6,请使用版本
6.0.*
然后,在您的 Startup.cs
中,在 ConfigureServices()
方法中将此更改为:
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddControllers();
// ...
}
为此:
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddControllers().AddNewtonsoftJson();
// ...
}
由于您只想按原样返回对象,请将代码更改为:
public async Task<object> GetItemAsync(string id)
{
try
{
var response = await this._container.ReadItemAsync<object>(id, new PartitionKey(id));
return response.Resource;
}
catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
{
return null;
}
}
不需要使用dynamic
。只需使用 object
.