ASP.NET Core基于文件的应用程序,默认序列化导致错误
我想把一个有基础API的简单应用,改造成一个用来对数字进行计算以产生负载的应用,作为一个概念验证的基于文件的应用。
generate-load-server.cs:
#! /usr/bin/env dotnet run
#:sdk Microsoft.NET.Sdk.Web
using Microsoft.AspNetCore.Mvc;
using System.Numerics;
var builder = WebApplication.CreateBuilder();
builder.Services.AddRequestTimeouts();
var app = builder.Build();
app.UseRequestTimeouts();
app.MapGet("/api/generate-load", ([FromQuery] int? n = default) =>
{
var iterations = n ?? 100000000;
ArgumentOutOfRangeException.ThrowIfNegative(iterations);
if (Vector.IsHardwareAccelerated)
return CalculatePi.MonteCarloVector(iterations);
return CalculatePi.MonteCarloBasic(iterations);
}).WithRequestTimeout(TimeSpan.FromMinutes(10));
await app.RunAsync("http://localhost:8123");
static class CalculatePi
{
// implementations...
public static decimal MonteCarloBasic(int iter, int? seed = default)
{
// ...
}
public static decimal MonteCarloVector(int iter, int? seed = default)
{
// ...
}
}
应用程序启动得很正常,但当我调用API时,遇到了一个怪异的JSON序列化错误,和我的代码完全无关。
$ dotnet run generate-load-server.cs
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://localhost:8123
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Production
info: Microsoft.Hosting.Lifetime[0]
Content root path: S:\test
info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
Request starting HTTP/1.1 GET http://localhost:8123/api/generate-load?n=1000000000 - - -
bunch of requests...
info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
Request starting HTTP/1.1 GET http://localhost:8123/api/generate-load?n=1000000000 - - -
fail: Microsoft.AspNetCore.Server.Kestrel[13]
Connection id "0HNKN8P5M7SO1", Request id "0HNKN8P5M7SO1:00000001": An unhandled exception was thrown by the application.
System.NotSupportedException: JsonTypeInfo metadata for type 'System.Decimal' was not provided by TypeInfoResolver of type '[]'. If using source generation, ensure that all root types passed to the serializer have been annotated with 'JsonSerializableAttribute', along with any types that might be serialized polymorphically.
at System.Text.Json.ThrowHelper.ThrowNotSupportedException_NoMetadataForType(Type type, IJsonTypeInfoResolver resolver)
at System.Text.Json.JsonSerializerOptions.GetTypeInfoInternal(Type type, Boolean ensureConfigured, Nullable`1 ensureNotNull, Boolean resolveIfMutable, Boolean fallBackToNearestAncestorType)
at System.Text.Json.JsonSerializerOptions.GetTypeInfo(Type type)
at Microsoft.AspNetCore.Http.Generated.<GeneratedRouteBuilderExtensions_g>F6DE0C89F6F8484B82B89F44B1C0701B89E2552B502F347FA7B76C4935F008AA9__GeneratedRouteBuilderExtensionsCore.<>c.<MapGet0>b__2_1(Delegate del, RequestDelegateFactoryOptions options, RequestDelegateMetadataResult inferredMetadataResult) in C:\Users\jeff.mercado\AppData\Local\Temp\dotnet\runfile\generate-load-server-165da69c96b0c4ee5a200ebe536be4b7bab40e25dcdf29f15f61d54c4d7f526c\obj\debug\Microsoft.AspNetCore.Http.RequestDelegateGenerator\Microsoft.AspNetCore.Http.RequestDelegateGenerator.RequestDelegateGenerator\GeneratedRouteBuilderExtensions.g.cs:line 92
at Microsoft.AspNetCore.Routing.RouteEndpointDataSource.CreateRouteEndpointBuilder(RouteEntry entry, RoutePattern groupPrefix, IReadOnlyList`1 groupConventions, IReadOnlyList`1 groupFinallyConventions)
at Microsoft.AspNetCore.Routing.RouteEndpointDataSource.get_Endpoints()
at Microsoft.AspNetCore.Routing.CompositeEndpointDataSource.CreateEndpointsUnsynchronized()
at Microsoft.AspNetCore.Routing.CompositeEndpointDataSource.EnsureEndpointsInitialized()
at Microsoft.AspNetCore.Routing.CompositeEndpointDataSource.get_Endpoints()
at Microsoft.AspNetCore.Routing.DataSourceDependentCache`1.Initialize()
at System.Threading.LazyInitializer.EnsureInitializedCore[T](T& target, Boolean& initialized, Object& syncLock, Func`1 valueFactory)
at Microsoft.AspNetCore.Routing.Matching.DataSourceDependentMatcher..ctor(EndpointDataSource dataSource, Lifetime lifetime, Func`1 matcherBuilderFactory)
at Microsoft.AspNetCore.Routing.Matching.DfaMatcherFactory.CreateMatcher(EndpointDataSource dataSource)
at Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.InitializeCoreAsync()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.<Invoke>g__AwaitMatcher|10_0(EndpointRoutingMiddleware middleware, HttpContext httpContext, Task`1 matcherTask)
at Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.<Invoke>g__AwaitMatcher|10_0(EndpointRoutingMiddleware middleware, HttpContext httpContext, Task`1 matcherTask)
at Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.<Invoke>g__AwaitMatcher|10_0(EndpointRoutingMiddleware middleware, HttpContext httpContext, Task`1 matcherTask)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)
bunch of this error...
System.NotSupportedException: JsonTypeInfo metadata for type 'System.Decimal' was not provided by TypeInfoResolver of type '[]'. If using source generation, ensure that all root types passed to the serializer have been annotated with 'JsonSerializableAttribute', along with any types that might be serialized polymorphically.
那它突然就不知道如何对decimal类型进行序列化吗?
同样的代码在LINQPad运行时没有问题,但出于某种原因,序列化配置存在问题。我需要添加额外的引用/配置吗?为什么要为内置的decimal重新定义序列化?
我已经安装了.NET 11的预览版本,并添加一个 global.json 文件来强制它使用.NET 10,但这没有任何效果。
global.json:
{
"sdk": {
"version": "10.0.201"
}
}
这个错误的原因是什么?我该如何修复?
解决方案
基于文件的应用默认使用原生的提前编译(AOT):
File-based apps enable native ahead-of-time (AOT) compilation by default. This feature produces optimized, self-contained executables with faster startup and a smaller memory footprint.
你可以启用ASP.NET Core的源生代码生成支持(你已经发现过):
[JsonSerializable(typeof(decimal))]
internal partial class MyJsonContext : JsonSerializerContext { }
builder.Services.ConfigureHttpJsonOptions(o =>
{
o.SerializerOptions.TypeInfoResolverChain.Insert(0, MyJsonContext.Default);
});
或者通过相应的设置禁用本地AOT,例如在文件顶部指定以下内容:
:property PublishAot=false
对于像ASP.NET Core服务这样的长期运行应用,我建议直接禁用AOT选项。