diff --git a/Directory.Packages.props b/Directory.Packages.props
index f5b88463bd..5d63f56ecf 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -73,13 +73,13 @@
AggregateType (TypeDescriptor), populated in the shared
SubscriptionDescriptor(ISubscriptionSource, IEventStore) ctor that Marten's projections
funnel through via ProjectionGraph.Describe. See marten#4772. -->
-
-
-
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
diff --git a/src/ContainerScopedProjectionTests/Bug_4787_di_projection_with_instance_apply.cs b/src/ContainerScopedProjectionTests/Bug_4787_di_projection_with_instance_apply.cs
new file mode 100644
index 0000000000..cc2388f50e
--- /dev/null
+++ b/src/ContainerScopedProjectionTests/Bug_4787_di_projection_with_instance_apply.cs
@@ -0,0 +1,264 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using JasperFx.Events;
+using JasperFx.Events.Projections;
+using Marten;
+using Marten.Events.Aggregation;
+using Marten.Testing.Harness;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using Npgsql;
+using Shouldly;
+using Weasel.Postgresql;
+using Xunit;
+
+namespace ContainerScopedProjectionTests;
+
+///
+/// Repro for https://github.com/JasperFx/marten/issues/4787. A
+/// registered via
+/// AddProjectionWithServices with constructor-injected dependencies
+/// and conventional instance methods (Create / Apply /
+/// ShouldDelete) has its dependencies silently NULL inside every
+/// convention method on Marten 9.11+ / JasperFx.Events 2.14.x+. The
+/// reporter's original "silent zero events" symptom came from a downstream
+/// null-conditional masking the NRE; these tests deref the injected
+/// service directly so the failure surfaces deterministically.
+///
+/// Root cause is visible in the generated Evolver (file is in
+/// obj/.../OrderProjection.Evolver.g.cs):
+///
+/// _projection => _projectionInstance ??= (OrderProjection)
+/// RuntimeHelpers.GetUninitializedObject(typeof(OrderProjection));
+///
+/// That bypasses the constructor entirely — added in jasperfx#470 /
+/// JasperFx 2.14.1 commit 1b728d1
+/// (EvolverCodeEmitter.cs:152-163) to make DI-only-ctor projections
+/// compile (previously CS7036). It fixed compilation but introduced this
+/// runtime regression: tryUseAssemblyRegisteredEvolver
+/// (JasperFxAggregationProjectionBase.cs:222) routes every Apply /
+/// Create / ShouldDelete through the uninitialized shadow, so the
+/// DI-resolved projection that AddProjectionWithServices supplied
+/// is never used for event dispatch.
+///
+/// Coverage matrix: 3 convention methods × 3
+/// values = 9 cases, all expected to fail today the same way and to pass
+/// once the dispatcher routes through the DI-built instance.
+///
+/// Note that AddProjectionWithServices documents Transient as
+/// "treated as Scoped" — we still parameterize over all three so any
+/// future per-lifetime divergence is captured.
+///
+[Collection("ioc")]
+public class Bug_4787_di_projection_with_instance_apply
+{
+ [Theory]
+ [InlineData(ServiceLifetime.Singleton)]
+ [InlineData(ServiceLifetime.Scoped)]
+ [InlineData(ServiceLifetime.Transient)]
+ public async Task Create_convention_sees_injected_dependency(ServiceLifetime lifetime)
+ {
+ var recorder = await runScenario("create", lifetime, append =>
+ {
+ // Stream-start event triggers the Create convention.
+ append(new OrderCreatedEvent { OrderNumber = "X", Version = 1 });
+ });
+
+ recorder.Created.Count.ShouldBe(1);
+ recorder.Created[0].ShouldBeOfType();
+ }
+
+ [Theory]
+ [InlineData(ServiceLifetime.Singleton)]
+ [InlineData(ServiceLifetime.Scoped)]
+ [InlineData(ServiceLifetime.Transient)]
+ public async Task Apply_convention_sees_injected_dependency(ServiceLifetime lifetime)
+ {
+ var recorder = await runScenario("apply", lifetime, append =>
+ {
+ // Create first to materialize the snapshot, then Apply runs for
+ // the second event.
+ append(new OrderCreatedEvent { OrderNumber = "X", Version = 1 });
+ append(new OrderUpdatedEvent { OrderNumber = "X", Version = 2, Total = 42m });
+ });
+
+ recorder.Applied.Count.ShouldBe(1);
+ recorder.Applied[0].ShouldBeOfType();
+ }
+
+ [Theory]
+ [InlineData(ServiceLifetime.Singleton)]
+ [InlineData(ServiceLifetime.Scoped)]
+ [InlineData(ServiceLifetime.Transient)]
+ public async Task ShouldDelete_convention_sees_injected_dependency(ServiceLifetime lifetime)
+ {
+ var recorder = await runScenario("delete", lifetime, append =>
+ {
+ // Create + Closed sequence — ShouldDelete is the predicate that
+ // tombstones the aggregate when a Closed event arrives.
+ append(new OrderCreatedEvent { OrderNumber = "X", Version = 1 });
+ append(new OrderClosedEvent { OrderNumber = "X", Version = 2 });
+ });
+
+ recorder.ShouldDeleteChecked.Count.ShouldBe(1);
+ recorder.ShouldDeleteChecked[0].ShouldBeOfType();
+ }
+
+ private static async Task runScenario(
+ string scenario, ServiceLifetime lifetime, Action> arrange)
+ {
+ // Per-scenario, per-lifetime schema so test cases don't collide.
+ // Compact name to stay well under PostgreSQL's 63-char identifier limit.
+ var schema = $"b4787_{scenario}_{lifetime.ToString().ToLowerInvariant()}";
+
+ await using (var conn = new NpgsqlConnection(ConnectionSource.ConnectionString))
+ {
+ await conn.OpenAsync();
+ await conn.DropSchemaAsync(schema);
+ await conn.CloseAsync();
+ }
+
+ var recorder = new OrderEventRecorder();
+
+ using var host = await Host.CreateDefaultBuilder()
+ .ConfigureServices(services =>
+ {
+ services.AddSingleton(recorder);
+
+ services.AddMarten(opts =>
+ {
+ opts.Connection(ConnectionSource.ConnectionString);
+ opts.DatabaseSchemaName = schema;
+ opts.Events.StreamIdentity = StreamIdentity.AsString;
+ opts.Schema.For().Identity(x => x.OrderNumber);
+ })
+ .AddProjectionWithServices(ProjectionLifecycle.Inline, lifetime);
+ })
+ .StartAsync();
+
+ var store = host.Services.GetRequiredService();
+
+ var events = new List();
+ arrange(events.Add);
+
+ await using (var session = store.LightweightSession())
+ {
+ session.Events.StartStream("X", events.Cast