Skip to content

Commit 8b3e364

Browse files
committed
Strengthen NativeAOT regression coverage
1 parent ef0088b commit 8b3e364

4 files changed

Lines changed: 50 additions & 5 deletions

File tree

.github/workflows/build-linux.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,7 @@ jobs:
2929
run: dotnet test --configuration Release --no-build Exceptionless.Net.NonWindows.slnx
3030
- name: NativeAOT Smoke Test
3131
run: |
32-
dotnet publish --configuration Release --output artifacts/aot-smoke test/Exceptionless.AotSmoke/Exceptionless.AotSmoke.csproj
33-
./artifacts/aot-smoke/Exceptionless.AotSmoke
32+
for framework in net8.0 net10.0; do
33+
dotnet publish --configuration Release --framework "$framework" --output "artifacts/aot-smoke/$framework" test/Exceptionless.AotSmoke/Exceptionless.AotSmoke.csproj
34+
"./artifacts/aot-smoke/$framework/Exceptionless.AotSmoke"
35+
done

docs/plans/2026-07-12-modern-di-stj-plan.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
2. Use an Exceptionless-owned `JsonSerializerContext` for the wire model and accept a consumer resolver/context for arbitrary event data.
3636
3. Require NativeAOT consumers to register services and custom payload metadata explicitly; retain reflection and unregistered concrete activation only for dynamic-code runtimes.
3737
4. Use regular runtime stack traces on modern targets instead of the IL/PDB demystifier, while keeping exception capture and serialization functional with reduced metadata.
38-
5. Publish and execute a warning-as-error NativeAOT smoke application covering Microsoft DI, custom STJ metadata, storage, queues, submission, and nested exception capture in Linux CI.
38+
5. Publish and execute a warning-as-error NativeAOT smoke application for both `net8.0` and `net10.0`, covering default Microsoft DI/default serialization, custom STJ metadata, storage, queues, submission, and nested exception capture in Linux CI.
3939

4040
## Execution results
4141

@@ -45,4 +45,17 @@
4545
- Serializer coverage retains exact wire-format assertions and adds regressions for exclusions, depth limits, `DataDictionary` structured/raw values, settings coercion, and MessagePack marker round-trips.
4646
- `net462` core and `net472` test assemblies build with 0 warnings and 0 errors when Windows targeting is forced on macOS. Runtime execution of the .NET Framework tests still belongs in Windows CI.
4747
- The non-Windows solution packs successfully. A Windows-shaped core package containing both `net462` and `netstandard2.0` assets also packs successfully with explicit `SolutionDir`.
48-
- `net8.0` and `net10.0` core builds pass with 0 AOT/trim/single-file warnings. A real NativeAOT executable now covers Microsoft DI, source-generated custom payloads, storage round-trips, queued submission, and nested exception capture; Linux CI publishes and runs that executable with linker warnings treated as errors.
48+
- `net8.0` and `net10.0` core builds pass with 0 AOT/trim/single-file warnings. Real NativeAOT executables now cover default Microsoft DI/default serialization, source-generated custom payloads, storage round-trips, queued submission, and nested exception capture on both target frameworks; Linux CI publishes and runs them with linker warnings treated as errors.
49+
50+
## Historical NativeAOT comparison
51+
52+
The same strict NativeAOT client/serialization/storage probe was published and executed against four repository states:
53+
54+
| Commit | State | NativeAOT result |
55+
| --- | --- | --- |
56+
| `5eb567a` | Vendored Newtonsoft + TinyIoC | Published with 10 TinyIoC AOT/trim warnings, then exited 134 because TinyIoC could not construct `DefaultJsonSerializer`. |
57+
| `2dd1d8e` | System.Text.Json + TinyIoC | Same TinyIoC warnings and runtime construction failure. |
58+
| `118123b` | System.Text.Json + Microsoft DI before AOT hardening | Published with 4 DI trim warnings, then exited 134 because the serializer constructor was trimmed. |
59+
| `ef0088b` | Hardened System.Text.Json + Microsoft DI | Published with no product AOT/trim warnings and exited 0 with `AOT_HISTORY_PROBE_OK`. |
60+
61+
The legacy Newtonsoft serializer was also instantiated directly to remove TinyIoC as a confound. Under NativeAOT it serialized a normal POCO as `{}` and then failed built-in `Event` storage serialization because `SnakeCaseNamingStrategy` construction metadata had been trimmed. The pre-modernization client therefore had two independent NativeAOT blockers: TinyIoC and reflection-driven Newtonsoft serialization.

test/Exceptionless.AotSmoke/Exceptionless.AotSmoke.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
33
<OutputType>Exe</OutputType>
4-
<TargetFramework>net10.0</TargetFramework>
4+
<TargetFrameworks>net8.0;net10.0</TargetFrameworks>
55
<PublishAot>true</PublishAot>
66
<InvariantGlobalization>true</InvariantGlobalization>
77
<JsonSerializerIsReflectionEnabledByDefault>false</JsonSerializerIsReflectionEnabledByDefault>

test/Exceptionless.AotSmoke/Program.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,36 @@
1212
using Exceptionless.Submission;
1313
using Microsoft.Extensions.DependencyInjection;
1414

15+
using (var defaultClient = new ExceptionlessClient(configuration => {
16+
configuration.ApiKey = "00000000000000000000000000000000";
17+
configuration.IncludeModules = false;
18+
configuration.IncludePrivateInformation = false;
19+
configuration.UpdateSettingsWhenIdleInterval = System.TimeSpan.Zero;
20+
configuration.UseInMemoryStorage();
21+
})) {
22+
var defaultJsonSerializer = defaultClient.Configuration.Resolver.GetJsonSerializer();
23+
var defaultStorageSerializer = defaultClient.Configuration.Resolver.GetStorageSerializer();
24+
var builtInEvent = new Event {
25+
Type = Event.KnownTypes.Log,
26+
Source = "aot-default-services",
27+
Message = "NativeAOT default DI and serializer",
28+
Data = {
29+
["answer"] = 42,
30+
["enabled"] = true
31+
}
32+
};
33+
34+
string builtInJson = defaultJsonSerializer.Serialize(builtInEvent);
35+
Assert(builtInJson.Contains("\"source\":\"aot-default-services\""), "Default serializer lost a built-in event.");
36+
37+
using var defaultStream = new MemoryStream();
38+
defaultStorageSerializer.Serialize(builtInEvent, defaultStream);
39+
defaultStream.Position = 0;
40+
var defaultRoundTrip = defaultStorageSerializer.Deserialize<Event>(defaultStream);
41+
Assert(defaultRoundTrip.Source == builtInEvent.Source, "Default storage serializer lost a built-in event.");
42+
Assert(System.Convert.ToInt32(defaultRoundTrip.Data["answer"]) == 42, "Default storage serializer lost primitive event data.");
43+
}
44+
1545
var submissionClient = new CapturingSubmissionClient();
1646
var jsonSerializer = new DefaultJsonSerializer(AotSmokeJsonSerializerContext.Default);
1747
var services = new ServiceCollection();

0 commit comments

Comments
 (0)