System.NotSupportedException: 'MongoDB.Bson.Serialization.Serializers.DowncastingSerializer\2[System.Object,System.DateTime]' is missing native code or metadata. This can happen for code that is not compatible with trimming or AOT.`
Thrown at SpikerSoft.GameServer.Services.MongoPlaySessionRepository..ctor(IMongoDatabase database) → MongoIndexManager.CreateOne → LINQ index-key render → DowncastingSerializer.Create → Activator.CreateInstance. Because the repo is built at DI construction, IPlaySessionRepository (and its consumer PlayTimeTrackingService) can never be resolved — the GameServer container fails to start.
Root cause
SpikerSoft.GameServer is published NativeAOT (<PublishAot>true</PublishAot>, runtime-deps base image, native entrypoint — by design). MongoPlaySessionRepository's constructor built its indexes with strongly-typed lambdas:
IndexKeys.Ascending/Descending take Expression<Func<T, object>>, so s => s.StartedAt (a DateTimevalue type) compiles with a boxing Convert-to-object node. The driver's index renderer then reflectively constructs DowncastingSerializer<object, DateTime> via Activator.CreateInstance — a generic instantiation that AOT never compiled → NotSupportedException.
Fix (keeps AOT)
Backend PR incoming: define the two indexes with BsonDocument index keys ({ "UserId": 1, "StartedAt": -1 }, { "UserId": 1, "IsActive": 1 }), which render straight to field names with no expression translation or serializer construction — AOT-safe. The repository's filters/updates already use non-boxing Func<T,TField> expressions, so they don't hit this path and are unchanged.
Scope: only SpikerSoft.GameServer is AOT-published, and only MongoPlaySessionRepository builds indexes there, so the crash is contained. (Note: the same boxing-lambda index pattern exists in several SpikerSoft.Business services — OfflineAttemptStore, AnonymousSessionService, AnonymousLessonProgressService, KeycloakEventService — but those run under JIT in the API/workers, so they're fine today; they'd only need the same treatment if that code is ever AOT-published.)
Acceptance
GameServer starts under NativeAOT; game_play_sessions indexes are created; play-time tracking works. Unit tests pin the index field names/directions to PlaySession's class map. Final proof is an AOT-published smoke test (the reflective failure only manifests in an AOT runtime, not a JIT unit test).
Severity: High (production startup crash for a whole service).
## Live in production (Seq)
`System.NotSupportedException: 'MongoDB.Bson.Serialization.Serializers.DowncastingSerializer\`2[System.Object,System.DateTime]' is missing native code or metadata. This can happen for code that is not compatible with trimming or AOT.`
Thrown at `SpikerSoft.GameServer.Services.MongoPlaySessionRepository..ctor(IMongoDatabase database)` → `MongoIndexManager.CreateOne` → LINQ index-key render → `DowncastingSerializer.Create` → `Activator.CreateInstance`. Because the repo is built at DI construction, `IPlaySessionRepository` (and its consumer `PlayTimeTrackingService`) can never be resolved — the GameServer container fails to start.
## Root cause
`SpikerSoft.GameServer` is published **NativeAOT** (`<PublishAot>true</PublishAot>`, `runtime-deps` base image, native entrypoint — by design). `MongoPlaySessionRepository`'s constructor built its indexes with strongly-typed lambdas:
```csharp
Builders<PlaySession>.IndexKeys.Ascending(s => s.UserId).Descending(s => s.StartedAt)
```
`IndexKeys.Ascending/Descending` take `Expression<Func<T, object>>`, so `s => s.StartedAt` (a `DateTime` **value type**) compiles with a boxing `Convert`-to-`object` node. The driver's index renderer then reflectively constructs `DowncastingSerializer<object, DateTime>` via `Activator.CreateInstance` — a **generic instantiation that AOT never compiled** → `NotSupportedException`.
## Fix (keeps AOT)
Backend PR incoming: define the two indexes with **`BsonDocument` index keys** (`{ "UserId": 1, "StartedAt": -1 }`, `{ "UserId": 1, "IsActive": 1 }`), which render straight to field names with no expression translation or serializer construction — AOT-safe. The repository's filters/updates already use non-boxing `Func<T,TField>` expressions, so they don't hit this path and are unchanged.
Scope: only `SpikerSoft.GameServer` is AOT-published, and only `MongoPlaySessionRepository` builds indexes there, so the crash is contained. (Note: the same boxing-lambda index pattern exists in several `SpikerSoft.Business` services — `OfflineAttemptStore`, `AnonymousSessionService`, `AnonymousLessonProgressService`, `KeycloakEventService` — but those run under JIT in the API/workers, so they're fine today; they'd only need the same treatment if that code is ever AOT-published.)
## Acceptance
GameServer starts under NativeAOT; `game_play_sessions` indexes are created; play-time tracking works. Unit tests pin the index field names/directions to PlaySession's class map. **Final proof is an AOT-published smoke test** (the reflective failure only manifests in an AOT runtime, not a JIT unit test).
Severity: **High** (production startup crash for a whole service).
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Live in production (Seq)
System.NotSupportedException: 'MongoDB.Bson.Serialization.Serializers.DowncastingSerializer\2[System.Object,System.DateTime]' is missing native code or metadata. This can happen for code that is not compatible with trimming or AOT.`Thrown at
SpikerSoft.GameServer.Services.MongoPlaySessionRepository..ctor(IMongoDatabase database)→MongoIndexManager.CreateOne→ LINQ index-key render →DowncastingSerializer.Create→Activator.CreateInstance. Because the repo is built at DI construction,IPlaySessionRepository(and its consumerPlayTimeTrackingService) can never be resolved — the GameServer container fails to start.Root cause
SpikerSoft.GameServeris published NativeAOT (<PublishAot>true</PublishAot>,runtime-depsbase image, native entrypoint — by design).MongoPlaySessionRepository's constructor built its indexes with strongly-typed lambdas:IndexKeys.Ascending/DescendingtakeExpression<Func<T, object>>, sos => s.StartedAt(aDateTimevalue type) compiles with a boxingConvert-to-objectnode. The driver's index renderer then reflectively constructsDowncastingSerializer<object, DateTime>viaActivator.CreateInstance— a generic instantiation that AOT never compiled →NotSupportedException.Fix (keeps AOT)
Backend PR incoming: define the two indexes with
BsonDocumentindex keys ({ "UserId": 1, "StartedAt": -1 },{ "UserId": 1, "IsActive": 1 }), which render straight to field names with no expression translation or serializer construction — AOT-safe. The repository's filters/updates already use non-boxingFunc<T,TField>expressions, so they don't hit this path and are unchanged.Scope: only
SpikerSoft.GameServeris AOT-published, and onlyMongoPlaySessionRepositorybuilds indexes there, so the crash is contained. (Note: the same boxing-lambda index pattern exists in severalSpikerSoft.Businessservices —OfflineAttemptStore,AnonymousSessionService,AnonymousLessonProgressService,KeycloakEventService— but those run under JIT in the API/workers, so they're fine today; they'd only need the same treatment if that code is ever AOT-published.)Acceptance
GameServer starts under NativeAOT;
game_play_sessionsindexes are created; play-time tracking works. Unit tests pin the index field names/directions to PlaySession's class map. Final proof is an AOT-published smoke test (the reflective failure only manifests in an AOT runtime, not a JIT unit test).Severity: High (production startup crash for a whole service).