ServiceStack 客户端启用 PublishAot 后报错,如何解决?
结论
仅添加 <PublishAot>true</PublishAot>,不能保证 JsonServiceClient 在 Native AOT 下正常运行。对于这个简单的 JSON GET 请求,如果必须使用 Native AOT,可以改用 HttpClient,通过 System.Text.Json 源生成提供反序列化所需的类型信息。
题目没有提供具体的 .NET SDK 和 ServiceStack 包版本,因此无法认定所有版本、所有 ServiceStack 客户端都不支持 AOT,也无法保证某个配置能修复当前异常。ServiceStack 维护者在 2024 年关于 iOS/AOT 的讨论中提到过支持限制,但该讨论有特定的平台和时间背景,不能直接作为所有后续版本的兼容性结论。ServiceStack 维护者说明
为什么普通运行正常,AOT 发布后失败?
Native AOT 在发布时提前编译代码,并要求进行裁剪分析。如果调用路径依赖运行时动态生成代码,或通过反射访问未被保留的成员,程序可能在发布后失败。普通运行成功,不能证明相同代码满足这些限制。.NET Native AOT 文档
异常只在 AOT 发布后出现,可以优先排查客户端内部的 AOT 和裁剪兼容性。不过,ArgumentNullException 中的 method 只是异常参数名。仅凭这段堆栈,无法确定具体哪个方法或哪项元数据缺失,也不能断定 DTO 一定被裁剪了。
示例代码还有一处不一致:
var results = await client.GetAsync<List<fake>>("posts");
await 后得到的是 List<fake>,后续应使用:
Console.WriteLine($"got {results.Count}");
原代码中的 results.Result.Count 与这个返回类型不符。应先让最小复现代码与实际运行代码一致;这处修改本身不能解决 ServiceStack 内部的 AOT 兼容性问题。
必须使用 Native AOT 时,如何改写?
下面的示例保留原有 DTO 属性名,改用 HttpClient 请求接口,并显式传入源生成的 JsonTypeInfo。Microsoft 文档建议在 Native AOT 场景中使用 JSON 源生成,避免依赖默认的反射序列化路径。System.Text.Json 源生成文档
将控制台程序的 Program.cs 改为:
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Json;
using System.Text.Json.Serialization;
using var client = new HttpClient
{
BaseAddress = new Uri("https://jsonplaceholder.typicode.com/")
};
var results = await client.GetFromJsonAsync(
"posts",
AppJsonContext.Default.PostList);
if (results is null)
{
throw new InvalidOperationException("响应 JSON 为 null。");
}
Console.WriteLine($"got {results.Count}");
public class fake
{
[JsonPropertyName("userId")]
public int userid { get; set; }
public int id { get; set; }
public string title { get; set; } = "";
public string body { get; set; } = "";
}
[JsonSerializable(typeof(List<fake>), TypeInfoPropertyName = "PostList")]
internal partial class AppJsonContext : JsonSerializerContext
{
}
示例中:
[JsonSerializable]注册实际响应类型List<fake>。GetFromJsonAsync使用接收JsonTypeInfo的重载,将生成的类型信息传入反序列化过程。[JsonPropertyName("userId")]明确将 JSON 的userId映射到原有属性userid,避免依赖大小写匹配设置。
在支持 Native AOT 的 .NET 控制台项目中,保留以下发布配置:
<PropertyGroup>
<PublishAot>true</PublishAot>
</PropertyGroup>
按目标平台发布。例如,目标为 Linux x64 时:
dotnet publish -c Release -r linux-x64
linux-x64 需要按实际部署平台替换,构建环境也必须满足目标平台的 Native AOT 工具链要求。验证时,应运行发布目录中的原生可执行文件。示例会输出实际返回的列表数量;题目中的 got 100 是原始运行结果,不是这里重新测试得到的结果。
如果需要继续使用 ServiceStack 客户端
先记录 .NET SDK、目标框架、ServiceStack 包版本和发布目标,再检查发布日志中的裁剪与 AOT 警告。修复或解释这些警告,比单纯隐藏警告更有助于定位问题。
ServiceStack 文档提供了让 JsonApiClient 使用 System.Text.Json 的配置:
ClientConfig.UseSystemJson = UseSystemJson.Always;
切换 JSON 序列化器意味着序列化路径发生了变化,但不能证明整个客户端调用链已兼容 Native AOT。是否能使用源生成上下文,以及是否仍有其他不兼容路径,需要结合具体版本确认。ServiceStack System.Text.Json 文档
如果当前版本没有适用的兼容性保证,而项目又必须保留现有客户端,可以先关闭 Native AOT,使用普通 .NET 发布方式。不要把给 fake 添加成员保留标记当作通用修复:保留反射元数据无法解决所有运行时动态代码生成问题。
备注:内容仅供参考。
