diff --git a/Eventuous.slnx b/Eventuous.slnx index e32a93a74..1af57601b 100644 --- a/Eventuous.slnx +++ b/Eventuous.slnx @@ -52,6 +52,7 @@ + diff --git a/samples/kurrentdb/Bookings/Bookings.csproj b/samples/kurrentdb/Bookings/Bookings.csproj index 361244a4b..2d46cb2c6 100644 --- a/samples/kurrentdb/Bookings/Bookings.csproj +++ b/samples/kurrentdb/Bookings/Bookings.csproj @@ -35,6 +35,7 @@ + diff --git a/samples/kurrentdb/Bookings/Program.cs b/samples/kurrentdb/Bookings/Program.cs index ec51b0fd3..0060b1549 100644 --- a/samples/kurrentdb/Bookings/Program.cs +++ b/samples/kurrentdb/Bookings/Program.cs @@ -22,7 +22,7 @@ // .WriteTo.Seq("http://localhost:5341") .CreateLogger(); -DefaultEventSerializer.SetDefaultSerializer(new DefaultStaticEventSerializer(new SourceGenerationContext())); +EventSerializer.SetDefault(new DefaultStaticEventSerializer(new SourceGenerationContext())); var builder = WebApplication.CreateBuilder(args); builder.Host.UseSerilog(); diff --git a/samples/kurrentdb/Bookings/Registrations.cs b/samples/kurrentdb/Bookings/Registrations.cs index 1f7c0ebbf..66e58b300 100644 --- a/samples/kurrentdb/Bookings/Registrations.cs +++ b/samples/kurrentdb/Bookings/Registrations.cs @@ -23,7 +23,7 @@ namespace Bookings; public static class Registrations { extension(IServiceCollection services) { public void AddEventuous(IConfiguration configuration) { - DefaultEventSerializer.SetDefaultSerializer( + EventSerializer.SetDefault( new DefaultEventSerializer(new JsonSerializerOptions(JsonSerializerDefaults.Web).ConfigureForNodaTime(DateTimeZoneProviders.Tzdb)) ); diff --git a/samples/postgres/Bookings/Bookings.csproj b/samples/postgres/Bookings/Bookings.csproj index 258c4d860..4ef641f59 100644 --- a/samples/postgres/Bookings/Bookings.csproj +++ b/samples/postgres/Bookings/Bookings.csproj @@ -31,5 +31,6 @@ + \ No newline at end of file diff --git a/samples/postgres/Bookings/Registrations.cs b/samples/postgres/Bookings/Registrations.cs index 78a7040a9..ce1f6d3dd 100644 --- a/samples/postgres/Bookings/Registrations.cs +++ b/samples/postgres/Bookings/Registrations.cs @@ -19,7 +19,7 @@ namespace Bookings; public static class Registrations { public static void AddEventuous(this IServiceCollection services, IConfiguration configuration) { - DefaultEventSerializer.SetDefaultSerializer( + EventSerializer.SetDefault( new DefaultEventSerializer(new JsonSerializerOptions(JsonSerializerDefaults.Web).ConfigureForNodaTime(DateTimeZoneProviders.Tzdb)) ); diff --git a/src/Azure/src/Eventuous.Azure.ServiceBus/Producers/ServiceBusProducer.cs b/src/Azure/src/Eventuous.Azure.ServiceBus/Producers/ServiceBusProducer.cs index 69305e0d9..6b1bfe2f1 100644 --- a/src/Azure/src/Eventuous.Azure.ServiceBus/Producers/ServiceBusProducer.cs +++ b/src/Azure/src/Eventuous.Azure.ServiceBus/Producers/ServiceBusProducer.cs @@ -40,7 +40,7 @@ public ServiceBusProducer( _options = options; _log = log; _sender = client.CreateSender(options.QueueOrTopicName, options.SenderOptions); - _serializer = serializer ?? DefaultEventSerializer.Instance; + _serializer = serializer ?? EventSerializer.Default; _messageBatchBuilder = new(_sender, this._serializer, options.AttributeNames, SetActivityMessageType); log?.LogInformation("ServiceBusProducer created for {QueueOrTopicName}", options.QueueOrTopicName); } diff --git a/src/Azure/test/Eventuous.Tests.Azure.ServiceBus/ConvertEventToMessage.cs b/src/Azure/test/Eventuous.Tests.Azure.ServiceBus/ConvertEventToMessage.cs index c537260ca..f30a0376c 100644 --- a/src/Azure/test/Eventuous.Tests.Azure.ServiceBus/ConvertEventToMessage.cs +++ b/src/Azure/test/Eventuous.Tests.Azure.ServiceBus/ConvertEventToMessage.cs @@ -9,7 +9,7 @@ public class ConvertEventToMessage { public ConvertEventToMessage() { var builder = new ServiceBusMessageBuilder( - DefaultEventSerializer.Instance, + EventSerializer.Default, "test-stream", new(), new() { @@ -97,7 +97,7 @@ public class WithMessagePropertiesInMetaData { public WithMessagePropertiesInMetaData() { var attributeNames = new ServiceBusMessageAttributeNames(); - var builder = new ServiceBusMessageBuilder(DefaultEventSerializer.Instance, "test-stream", attributeNames, new()); + var builder = new ServiceBusMessageBuilder(EventSerializer.Default, "test-stream", attributeNames, new()); _message = builder.CreateServiceBusMessage( new( diff --git a/src/Azure/test/Eventuous.Tests.Azure.ServiceBus/TestSetup.cs b/src/Azure/test/Eventuous.Tests.Azure.ServiceBus/TestSetup.cs new file mode 100644 index 000000000..65c9d9263 --- /dev/null +++ b/src/Azure/test/Eventuous.Tests.Azure.ServiceBus/TestSetup.cs @@ -0,0 +1,12 @@ +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Text.Json; + +namespace Eventuous.Tests.Azure.ServiceBus; + +static class TestSetup { + [ModuleInitializer] + [SuppressMessage("Usage", "CA2255")] + internal static void Initialize() + => EventSerializer.SetDefault(new DefaultEventSerializer(new(JsonSerializerDefaults.Web))); +} diff --git a/src/Core/src/Eventuous.Application/AggregateService/CommandService.cs b/src/Core/src/Eventuous.Application/AggregateService/CommandService.cs index 45111b4de..a48c79e1d 100644 --- a/src/Core/src/Eventuous.Application/AggregateService/CommandService.cs +++ b/src/Core/src/Eventuous.Application/AggregateService/CommandService.cs @@ -59,8 +59,6 @@ protected IDefineExpectedState On() /// Cancellation token /// of the execution /// - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public async Task> Handle(TCommand command, CancellationToken cancellationToken) where TCommand : class { if (!_handlers.TryGet(out var registeredHandler)) { Log.CommandHandlerNotFound(); diff --git a/src/Core/src/Eventuous.Application/Diagnostics/TracedCommandService.cs b/src/Core/src/Eventuous.Application/Diagnostics/TracedCommandService.cs index be3c6c81d..8de58ca9b 100644 --- a/src/Core/src/Eventuous.Application/Diagnostics/TracedCommandService.cs +++ b/src/Core/src/Eventuous.Application/Diagnostics/TracedCommandService.cs @@ -18,8 +18,6 @@ namespace Eventuous.Diagnostics; InnerService = appService; } - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public Task> Handle(TCommand command, CancellationToken cancellationToken) where TCommand : class => CommandServiceActivity.TryExecute( diff --git a/src/Core/src/Eventuous.Application/FunctionalService/CommandService.cs b/src/Core/src/Eventuous.Application/FunctionalService/CommandService.cs index 5563b2f2e..83f10e043 100644 --- a/src/Core/src/Eventuous.Application/FunctionalService/CommandService.cs +++ b/src/Core/src/Eventuous.Application/FunctionalService/CommandService.cs @@ -66,8 +66,6 @@ protected CommandService(IEventStore store, ITypeMapper? typeMap = null, AmendEv /// Command type /// instance /// Throws when there's no command handler was registered for the command type - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public async Task> Handle(TCommand command, CancellationToken cancellationToken) where TCommand : class { if (!_handlers.TryGet(out var registeredHandler)) { Log.CommandHandlerNotFound(); diff --git a/src/Core/src/Eventuous.Application/ICommandService.cs b/src/Core/src/Eventuous.Application/ICommandService.cs index 132aa39df..b6b4fe241 100644 --- a/src/Core/src/Eventuous.Application/ICommandService.cs +++ b/src/Core/src/Eventuous.Application/ICommandService.cs @@ -6,8 +6,6 @@ namespace Eventuous; public interface ICommandService where TState : State, new() { - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] Task> Handle(TCommand command, CancellationToken cancellationToken) where TCommand : class; } diff --git a/src/Core/src/Eventuous.Application/Persistence/WriterExtensions.cs b/src/Core/src/Eventuous.Application/Persistence/WriterExtensions.cs index 88213674c..b7a80e87f 100644 --- a/src/Core/src/Eventuous.Application/Persistence/WriterExtensions.cs +++ b/src/Core/src/Eventuous.Application/Persistence/WriterExtensions.cs @@ -5,8 +5,6 @@ namespace Eventuous.Persistence; static class WriterExtensions { extension(IEventWriter writer) { - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public async Task Store(ProposedAppend append, AmendEvent? amendEvent, CancellationToken cancellationToken) { Ensure.NotNull(append.Events); @@ -33,8 +31,6 @@ NewStreamEvent ToStreamEvent(ProposedEvent evt) { } } - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public async Task Store( IReadOnlyCollection appends, AmendEvent? amendEvent, diff --git a/src/Core/src/Eventuous.Application/ThrowingCommandService.cs b/src/Core/src/Eventuous.Application/ThrowingCommandService.cs index 296e9e629..cc49091de 100644 --- a/src/Core/src/Eventuous.Application/ThrowingCommandService.cs +++ b/src/Core/src/Eventuous.Application/ThrowingCommandService.cs @@ -10,8 +10,6 @@ namespace Eventuous; /// public class ThrowingCommandService(ICommandService inner) : ICommandService where TState : State, new() { - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public async Task> Handle(TCommand command, CancellationToken cancellationToken) where TCommand : class { var result = await inner.Handle(command, cancellationToken); diff --git a/src/Core/src/Eventuous.Persistence/AggregateStore/AggregatePersistenceExtensions.cs b/src/Core/src/Eventuous.Persistence/AggregateStore/AggregatePersistenceExtensions.cs index 1907e364a..8f9c7cc14 100644 --- a/src/Core/src/Eventuous.Persistence/AggregateStore/AggregatePersistenceExtensions.cs +++ b/src/Core/src/Eventuous.Persistence/AggregateStore/AggregatePersistenceExtensions.cs @@ -20,8 +20,6 @@ public static class AggregatePersistenceExtensions { /// Aggregate state type /// Append event result /// Gets thrown if the expected stream version mismatches with the given original stream version - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public async Task StoreAggregate( StreamName streamName, TAggregate aggregate, @@ -52,8 +50,6 @@ public async Task StoreAggregate( /// Aggregate identity type /// Append event result /// Gets thrown if the expected stream version mismatches with the given original stream version - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public Task StoreAggregate( TAggregate aggregate, TId id, @@ -84,8 +80,6 @@ public Task StoreAggregate( /// Aggregate identity type /// Append event result /// Gets thrown if the expected stream version mismatches with the given original stream version - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public Task StoreAggregate( TAggregate aggregate, StreamNameMap? streamNameMap = null, @@ -115,8 +109,6 @@ public Task StoreAggregate( /// Aggregate instance /// If failIfNotFound set to true, this exception is thrown if there's no stream /// - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public async Task LoadAggregate<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] TAggregate, TState>( StreamName streamName, bool failIfNotFound = true, @@ -155,8 +147,6 @@ public Task StoreAggregate( /// Aggregate instance /// If failIfNotFound set to true, this exception is thrown if there's no stream /// - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public async Task LoadAggregate<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] TAggregate, TState, TId>( TId aggregateId, StreamNameMap? streamNameMap = null, diff --git a/src/Core/src/Eventuous.Persistence/AggregateStore/AggregateStore.cs b/src/Core/src/Eventuous.Persistence/AggregateStore/AggregateStore.cs index aeda1b036..3884b355b 100644 --- a/src/Core/src/Eventuous.Persistence/AggregateStore/AggregateStore.cs +++ b/src/Core/src/Eventuous.Persistence/AggregateStore/AggregateStore.cs @@ -32,23 +32,17 @@ public AggregateStore( /// [Obsolete("Use IEventWriter.StoreAggregate instead.")] - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public Task Store(StreamName streamName, TAggregate aggregate, CancellationToken cancellationToken) where TAggregate : Aggregate where TState : State, new() => _eventWriter.StoreAggregate(streamName, aggregate, _amendEvent, cancellationToken); /// [Obsolete("Use IEventReader.LoadAggregate instead.")] - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public Task Load<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] T, TState>(StreamName streamName, CancellationToken cancellationToken) where T : Aggregate where TState : State, new() => _eventReader.LoadAggregate(streamName, true, _factoryRegistry, cancellationToken); /// [Obsolete("Use IEventReader.LoadAggregate instead.")] - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public Task LoadOrNew<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] T, TState>(StreamName streamName, CancellationToken cancellationToken) where T : Aggregate where TState : State, new() => _eventReader.LoadAggregate(streamName, false, _factoryRegistry, cancellationToken); diff --git a/src/Core/src/Eventuous.Persistence/AggregateStore/AggregateStoreExtensions.cs b/src/Core/src/Eventuous.Persistence/AggregateStore/AggregateStoreExtensions.cs index 296b78582..3f8fbc152 100644 --- a/src/Core/src/Eventuous.Persistence/AggregateStore/AggregateStoreExtensions.cs +++ b/src/Core/src/Eventuous.Persistence/AggregateStore/AggregateStoreExtensions.cs @@ -17,8 +17,6 @@ public static class AggregateStoreExtensions { /// Aggregate id type /// [Obsolete("Use IEventReader.LoadAggregates instead.")] - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public async Task Load <[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] T, TState, TId>(StreamNameMap streamNameMap, TId id, CancellationToken cancellationToken) where T : Aggregate where TId : Id where TState : State, new() { @@ -39,8 +37,6 @@ public async Task Load /// Aggregate id type /// [Obsolete("Use IEventReader.LoadAggregates instead.")] - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public async Task LoadOrNew<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] TAggregate, TState, TId>( StreamNameMap streamNameMap, TId id, diff --git a/src/Core/src/Eventuous.Persistence/AggregateStore/AggregateStoreWithArchive.cs b/src/Core/src/Eventuous.Persistence/AggregateStore/AggregateStoreWithArchive.cs index 52ae93beb..1e80ab7a6 100644 --- a/src/Core/src/Eventuous.Persistence/AggregateStore/AggregateStoreWithArchive.cs +++ b/src/Core/src/Eventuous.Persistence/AggregateStore/AggregateStoreWithArchive.cs @@ -15,22 +15,16 @@ public class AggregateStore( readonly TieredEventStore _tieredEventStore = new(eventStore, archiveReader); /// - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public Task Store(StreamName streamName, TAggregate aggregate, CancellationToken cancellationToken) where TAggregate : Aggregate where TState : State, new() => eventStore.StoreAggregate(streamName, aggregate, amendEvent, cancellationToken); /// - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public Task Load<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] TAggregate, TState>(StreamName streamName, CancellationToken cancellationToken) where TAggregate : Aggregate where TState : State, new() => _tieredEventStore.LoadAggregate(streamName, true, _factoryRegistry, cancellationToken); /// - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public Task LoadOrNew<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] TAggregate, TState>(StreamName streamName, CancellationToken cancellationToken) where TAggregate : Aggregate where TState : State, new() => _tieredEventStore.LoadAggregate(streamName, false, _factoryRegistry, cancellationToken); diff --git a/src/Core/src/Eventuous.Persistence/AggregateStore/IAggregateStore.cs b/src/Core/src/Eventuous.Persistence/AggregateStore/IAggregateStore.cs index a1eeeff67..df8631072 100644 --- a/src/Core/src/Eventuous.Persistence/AggregateStore/IAggregateStore.cs +++ b/src/Core/src/Eventuous.Persistence/AggregateStore/IAggregateStore.cs @@ -20,8 +20,6 @@ public interface IAggregateStore { /// Aggregate state type /// Result of the append operation [Obsolete("Use IEventWriter.StoreAggregate instead.")] - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public Task Store(TAggregate aggregate, TId id, CancellationToken cancellationToken) where TAggregate : Aggregate where TId : Id where TState : State, new() => Store(StreamNameFactory.For(id), aggregate, cancellationToken); @@ -36,8 +34,6 @@ public Task Store(TAggregate aggreg /// Aggregate state type /// Result of the append operation [Obsolete("Use IEventWriter.StoreAggregate instead.")] - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] Task Store(StreamName streamName, TAggregate aggregate, CancellationToken cancellationToken) where TAggregate : Aggregate where TState : State, new(); @@ -51,8 +47,6 @@ Task Store(StreamName streamName, TAggre /// Aggregate identity type /// Aggregate instance [Obsolete("Use IEventReader.LoadAggregate instead.")] - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public Task Load<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] TAggregate, TState, TId>(TId id, CancellationToken cancellationToken) where TAggregate : Aggregate where TId : Id where TState : State, new() => Load(StreamNameFactory.For(id), cancellationToken); @@ -66,8 +60,6 @@ Task Store(StreamName streamName, TAggre /// Aggregate state type /// Aggregate instance [Obsolete("Use IEventReader.LoadAggregate instead.")] - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] Task Load<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] TAggregate, TState>(StreamName streamName, CancellationToken cancellationToken) where TAggregate : Aggregate where TState : State, new(); @@ -82,8 +74,6 @@ Task Store(StreamName streamName, TAggre /// Aggregate identity type /// Aggregate instance [Obsolete("Use IEventReader.LoadAggregate instead.")] - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public Task LoadOrNew<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] TAggregate, TState, TId>(TId id, CancellationToken cancellationToken) where TAggregate : Aggregate where TId : Id where TState : State, new() => LoadOrNew(StreamNameFactory.For(id), cancellationToken); @@ -98,8 +88,6 @@ Task Store(StreamName streamName, TAggre /// Aggregate state type /// Aggregate instance [Obsolete("Use IEventReader.LoadAggregate instead.")] - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] Task LoadOrNew<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] TAggregate, TState>(StreamName streamName, CancellationToken cancellationToken) where TAggregate : Aggregate where TState : State, new(); } diff --git a/src/Core/src/Eventuous.Persistence/Constants.cs b/src/Core/src/Eventuous.Persistence/Constants.cs deleted file mode 100644 index 3f1af6160..000000000 --- a/src/Core/src/Eventuous.Persistence/Constants.cs +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (C) Eventuous HQ OÜ. All rights reserved -// Licensed under the Apache License, Version 2.0. - -namespace Eventuous; - -internal static class AttrConstants { - internal const string DynamicSerializationMessage = "Only works with AOT when using DefaultStaticEventSerializer"; -} diff --git a/src/Core/src/Eventuous.Persistence/Diagnostics/Tracing/TracedEventReader.cs b/src/Core/src/Eventuous.Persistence/Diagnostics/Tracing/TracedEventReader.cs index 1f37de407..f9b8048ff 100644 --- a/src/Core/src/Eventuous.Persistence/Diagnostics/Tracing/TracedEventReader.cs +++ b/src/Core/src/Eventuous.Persistence/Diagnostics/Tracing/TracedEventReader.cs @@ -14,13 +14,9 @@ public class TracedEventReader(IEventReader reader) : BaseTracer, IEventReader { IEventReader Inner { get; } = reader; - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public IAsyncEnumerable ReadEvents(StreamName stream, StreamReadPosition start, int count, CancellationToken cancellationToken) => TraceEnumerable(stream, Operations.ReadEvents, Inner.ReadEvents(stream, start, count, cancellationToken)); - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public IAsyncEnumerable ReadEventsBackwards(StreamName stream, StreamReadPosition start, int count, CancellationToken cancellationToken) => TraceEnumerable(stream, Operations.ReadEvents, Inner.ReadEventsBackwards(stream, start, count, cancellationToken)); diff --git a/src/Core/src/Eventuous.Persistence/Diagnostics/Tracing/TracedEventStore.cs b/src/Core/src/Eventuous.Persistence/Diagnostics/Tracing/TracedEventStore.cs index 0ed2fe8ea..4b0ab156c 100644 --- a/src/Core/src/Eventuous.Persistence/Diagnostics/Tracing/TracedEventStore.cs +++ b/src/Core/src/Eventuous.Persistence/Diagnostics/Tracing/TracedEventStore.cs @@ -20,8 +20,6 @@ public class TracedEventStore(IEventStore eventStore) : BaseTracer, IEventStore public Task StreamExists(StreamName stream, CancellationToken cancellationToken) => Trace(stream, Operations.StreamExists, () => Inner.StreamExists(stream, cancellationToken)); - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public Task AppendEvents( StreamName stream, ExpectedStreamVersion expectedVersion, @@ -30,18 +28,12 @@ CancellationToken cancellationToken ) => Writer.AppendEvents(stream, expectedVersion, events, cancellationToken); - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public Task AppendEvents(IReadOnlyCollection appends, CancellationToken cancellationToken) => Writer.AppendEvents(appends, cancellationToken); - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public IAsyncEnumerable ReadEvents(StreamName stream, StreamReadPosition start, int count, CancellationToken cancellationToken) => Reader.ReadEvents(stream, start, count, cancellationToken); - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public IAsyncEnumerable ReadEventsBackwards(StreamName stream, StreamReadPosition start, int count, CancellationToken cancellationToken) => Reader.ReadEventsBackwards(stream, start, count, cancellationToken); diff --git a/src/Core/src/Eventuous.Persistence/Diagnostics/Tracing/TracedEventWriter.cs b/src/Core/src/Eventuous.Persistence/Diagnostics/Tracing/TracedEventWriter.cs index 1df507c52..1c95d69a6 100644 --- a/src/Core/src/Eventuous.Persistence/Diagnostics/Tracing/TracedEventWriter.cs +++ b/src/Core/src/Eventuous.Persistence/Diagnostics/Tracing/TracedEventWriter.cs @@ -13,8 +13,6 @@ public class TracedEventWriter(IEventWriter writer) : BaseTracer, IEventWriter { readonly string _componentName = writer.GetType().Name; - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public async Task AppendEvents( StreamName stream, ExpectedStreamVersion expectedVersion, @@ -42,8 +40,6 @@ CancellationToken cancellationToken } } - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public async Task AppendEvents(IReadOnlyCollection appends, CancellationToken cancellationToken) { if (appends.Count == 0) return []; diff --git a/src/Core/src/Eventuous.Persistence/EventStore/IEventReader.cs b/src/Core/src/Eventuous.Persistence/EventStore/IEventReader.cs index c419dc194..8268287b9 100644 --- a/src/Core/src/Eventuous.Persistence/EventStore/IEventReader.cs +++ b/src/Core/src/Eventuous.Persistence/EventStore/IEventReader.cs @@ -13,8 +13,6 @@ public interface IEventReader { /// How many events to read /// Cancellation token /// An async enumerable of events retrieved from the stream - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] IAsyncEnumerable ReadEvents(StreamName stream, StreamReadPosition start, int count, CancellationToken cancellationToken); /// @@ -26,7 +24,5 @@ public interface IEventReader { /// How many events to read /// Cancellation token /// An async enumerable of events retrieved from the stream - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] IAsyncEnumerable ReadEventsBackwards(StreamName stream, StreamReadPosition start, int count, CancellationToken cancellationToken); } diff --git a/src/Core/src/Eventuous.Persistence/EventStore/IEventWriter.cs b/src/Core/src/Eventuous.Persistence/EventStore/IEventWriter.cs index cef4b6d2b..490f3568a 100644 --- a/src/Core/src/Eventuous.Persistence/EventStore/IEventWriter.cs +++ b/src/Core/src/Eventuous.Persistence/EventStore/IEventWriter.cs @@ -13,8 +13,6 @@ public interface IEventWriter { /// Cancellation token /// Append result, which contains the global position of the last written event, /// as well as the next stream version - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] Task AppendEvents( StreamName stream, ExpectedStreamVersion expectedVersion, @@ -30,8 +28,6 @@ CancellationToken cancellationToken /// Collection of stream appends to perform /// Cancellation token /// Array of append results, one per stream in the same order as input - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] async Task AppendEvents(IReadOnlyCollection appends, CancellationToken cancellationToken) { var results = new AppendEventsResult[appends.Count]; var i = 0; diff --git a/src/Core/src/Eventuous.Persistence/EventStore/StoreFunctions.cs b/src/Core/src/Eventuous.Persistence/EventStore/StoreFunctions.cs index ea230e84f..58c828d55 100644 --- a/src/Core/src/Eventuous.Persistence/EventStore/StoreFunctions.cs +++ b/src/Core/src/Eventuous.Persistence/EventStore/StoreFunctions.cs @@ -17,8 +17,6 @@ public static class StoreFunctions { /// Append events result /// Any exception that occurred in the event store /// Gets thrown if the expected stream version mismatches with the given original stream version - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public async Task Store( StreamName streamName, ExpectedStreamVersion expectedStreamVersion, @@ -53,8 +51,6 @@ NewStreamEvent ToStreamEvent(object evt) { } } - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public async Task Store( IReadOnlyCollection<(StreamName StreamName, ExpectedStreamVersion ExpectedVersion, IReadOnlyCollection Changes)> streams, AmendEvent? amendEvent = null, @@ -101,8 +97,6 @@ static NewStreamEvent ToStreamEvent(object evt, AmendEvent? amendEvent) { /// Throw an exception if the stream is not found /// Cancellation token /// An array with events retrieved from the stream - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public static async Task ReadEvents( this IEventReader eventReader, StreamName stream, @@ -135,8 +129,6 @@ CancellationToken cancellationToken /// Throw an exception if the stream is not found /// Cancellation token /// An array with events retrieved from the stream - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public static async Task ReadEventsBackwards( this IEventReader eventReader, StreamName stream, @@ -168,8 +160,6 @@ CancellationToken cancellationToken /// stream with the given name found in the store, the function will return an empty collection. /// Cancellation token /// Collection of events wrapped in - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public static async Task ReadStream( this IEventReader eventReader, StreamName streamName, diff --git a/src/Core/src/Eventuous.Persistence/EventStore/TieredEventReader.cs b/src/Core/src/Eventuous.Persistence/EventStore/TieredEventReader.cs index 758b2f888..3095489b8 100644 --- a/src/Core/src/Eventuous.Persistence/EventStore/TieredEventReader.cs +++ b/src/Core/src/Eventuous.Persistence/EventStore/TieredEventReader.cs @@ -12,8 +12,6 @@ namespace Eventuous; /// Event reader pointing to hot store /// Event reader pointing to archive store public class TieredEventReader(IEventReader hotReader, IEventReader archiveReader) : IEventReader { - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public async IAsyncEnumerable ReadEvents(StreamName streamName, StreamReadPosition start, int count, [EnumeratorCancellation] CancellationToken cancellationToken) { var hotEvents = await LoadStreamEvents(hotReader, streamName, start, count, cancellationToken).NoContext(); @@ -36,8 +34,6 @@ public async IAsyncEnumerable ReadEvents(StreamName streamName, Str if (!any) throw new StreamNotFound(streamName); } - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public async IAsyncEnumerable ReadEventsBackwards(StreamName streamName, StreamReadPosition start, int count, [EnumeratorCancellation] CancellationToken cancellationToken) { var hotEvents = await LoadStreamEvents(hotReader, streamName, start, count, cancellationToken, backwards: true).NoContext(); diff --git a/src/Core/src/Eventuous.Persistence/EventStore/TieredEventStore.cs b/src/Core/src/Eventuous.Persistence/EventStore/TieredEventStore.cs index a282a18d3..5d184f4a5 100644 --- a/src/Core/src/Eventuous.Persistence/EventStore/TieredEventStore.cs +++ b/src/Core/src/Eventuous.Persistence/EventStore/TieredEventStore.cs @@ -14,18 +14,12 @@ namespace Eventuous; public class TieredEventStore(IEventStore hotStore, IEventReader archiveReader) : IEventStore { readonly TieredEventReader _tieredReader = new(Ensure.NotNull(hotStore), Ensure.NotNull(archiveReader)); - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public IAsyncEnumerable ReadEvents(StreamName stream, StreamReadPosition start, int count, CancellationToken cancellationToken) => _tieredReader.ReadEvents(stream, start, count, cancellationToken); - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public IAsyncEnumerable ReadEventsBackwards(StreamName stream, StreamReadPosition start, int count, CancellationToken cancellationToken) => _tieredReader.ReadEventsBackwards(stream, start, count, cancellationToken); - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public Task AppendEvents( StreamName stream, ExpectedStreamVersion expectedVersion, @@ -33,8 +27,6 @@ public Task AppendEvents( CancellationToken cancellationToken ) => hotStore.AppendEvents(stream, expectedVersion, events, cancellationToken); - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public Task AppendEvents(IReadOnlyCollection appends, CancellationToken cancellationToken) => hotStore.AppendEvents(appends, cancellationToken); diff --git a/src/Core/src/Eventuous.Persistence/StateStore/IStateStore.cs b/src/Core/src/Eventuous.Persistence/StateStore/IStateStore.cs index 0a5418d0c..a8abcc707 100644 --- a/src/Core/src/Eventuous.Persistence/StateStore/IStateStore.cs +++ b/src/Core/src/Eventuous.Persistence/StateStore/IStateStore.cs @@ -18,7 +18,5 @@ public interface IStateStore { /// /// [Obsolete("Use IEventReader.LoadState instead")] - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] Task LoadState(StreamName stream, CancellationToken cancellationToken) where T : State, new(); } \ No newline at end of file diff --git a/src/Core/src/Eventuous.Persistence/StateStore/StateStore.cs b/src/Core/src/Eventuous.Persistence/StateStore/StateStore.cs index 8e1d29aac..5acdb3a37 100644 --- a/src/Core/src/Eventuous.Persistence/StateStore/StateStore.cs +++ b/src/Core/src/Eventuous.Persistence/StateStore/StateStore.cs @@ -9,13 +9,11 @@ namespace Eventuous; [Obsolete("Use IEventReader extension functions to load state")] public class StateStore(IEventReader eventReader, IEventSerializer? serializer = null) : IStateStore { readonly IEventReader _eventReader = Ensure.NotNull(eventReader); - readonly IEventSerializer _serializer = serializer ?? DefaultEventSerializer.Instance; + readonly IEventSerializer _serializer = serializer ?? EventSerializer.Default; const int PageSize = 500; [Obsolete("Use IEventReader.LoadState instead")] - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public async Task LoadState(StreamName stream, CancellationToken cancellationToken) where T : State, new() { var state = new T(); diff --git a/src/Core/src/Eventuous.Persistence/StateStore/StateStoreFunctions.cs b/src/Core/src/Eventuous.Persistence/StateStore/StateStoreFunctions.cs index 75d4667f0..9d32aaadb 100644 --- a/src/Core/src/Eventuous.Persistence/StateStore/StateStoreFunctions.cs +++ b/src/Core/src/Eventuous.Persistence/StateStore/StateStoreFunctions.cs @@ -17,8 +17,6 @@ public static class StateStoreFunctions { /// State object type /// Instance of containing events and folded state /// Thrown if there's no stream and failIfNotFound is true - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public async Task> LoadState( StreamName streamName, bool failIfNotFound = true, @@ -49,8 +47,6 @@ public async Task> LoadState( /// State object type /// State identity type /// Instance of containing events and folded state - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public async Task> LoadState( StreamNameMap streamNameMap, TId id, diff --git a/src/Core/src/Eventuous.Producers/BaseProducer.cs b/src/Core/src/Eventuous.Producers/BaseProducer.cs index 6763ccbc2..46e51fdf0 100644 --- a/src/Core/src/Eventuous.Producers/BaseProducer.cs +++ b/src/Core/src/Eventuous.Producers/BaseProducer.cs @@ -43,19 +43,13 @@ protected BaseProducer(ProducerTracingOptions? tracingOptions = null) { /// Produce options /// Cancellation token /// - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] protected abstract Task ProduceMessages(StreamName stream, IEnumerable messages, TProduceOptions? options, CancellationToken cancellationToken = default); /// - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public Task Produce(StreamName stream, IEnumerable messages, CancellationToken cancellationToken = default) => Produce(stream, messages, null, cancellationToken); /// - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public async Task Produce(StreamName stream, IEnumerable messages, TProduceOptions? options, CancellationToken cancellationToken = default) { var messagesArray = messages.ToArray(); if (messagesArray.Length == 0) return; @@ -85,15 +79,11 @@ public async Task Produce(StreamName stream, IEnumerable messag /// Collection of produce requests /// Cancellation token /// - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public Task Produce(IReadOnlyCollection> requests, CancellationToken cancellationToken = default) { return requests.Count == 0 ? Task.CompletedTask : Task.WhenAll(requests.Select(r => Produce(r.Stream, r.Messages, r.Options, cancellationToken))); } /// - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public Task Produce(IReadOnlyCollection requests, CancellationToken cancellationToken = default) { return requests.Count == 0 ? Task.CompletedTask : Task.WhenAll(requests.Select(r => Produce(r.Stream, r.Messages, cancellationToken))); } diff --git a/src/Core/src/Eventuous.Producers/Constants.cs b/src/Core/src/Eventuous.Producers/Constants.cs deleted file mode 100644 index 675660347..000000000 --- a/src/Core/src/Eventuous.Producers/Constants.cs +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (C) Eventuous HQ OÜ. All rights reserved -// Licensed under the Apache License, Version 2.0. - -namespace Eventuous.Producers; - -internal static class AttrConstants { - internal const string DynamicSerializationMessage = "Only works with AOT when using DefaultStaticEventSerializer"; -} diff --git a/src/Core/src/Eventuous.Producers/IProducer.cs b/src/Core/src/Eventuous.Producers/IProducer.cs index 8e44d8511..57b601e88 100644 --- a/src/Core/src/Eventuous.Producers/IProducer.cs +++ b/src/Core/src/Eventuous.Producers/IProducer.cs @@ -13,8 +13,6 @@ public interface IProducer { /// Collection of messages to produce /// /// - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] Task Produce(StreamName stream, IEnumerable messages, CancellationToken cancellationToken = default); /// @@ -23,8 +21,6 @@ public interface IProducer { /// Collection of produce requests, one per target stream /// /// - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] Task Produce(IReadOnlyCollection requests, CancellationToken cancellationToken = default) => Task.WhenAll(requests.Select(r => Produce(r.Stream, r.Messages, cancellationToken))); } @@ -39,8 +35,6 @@ public interface IProducer : IProducer where TProduceOptions /// Produce options /// /// - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] Task Produce(StreamName stream, IEnumerable messages, TProduceOptions? options, CancellationToken cancellationToken = default); } diff --git a/src/Core/src/Eventuous.Producers/ProducerExtensions.cs b/src/Core/src/Eventuous.Producers/ProducerExtensions.cs index 9e042dd65..29eeb42e4 100644 --- a/src/Core/src/Eventuous.Producers/ProducerExtensions.cs +++ b/src/Core/src/Eventuous.Producers/ProducerExtensions.cs @@ -19,8 +19,6 @@ public static class ProducerExtensions { /// /// Message typ /// - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public static Task Produce( this IProducer producer, StreamName stream, @@ -55,8 +53,6 @@ public static Task Produce( /// Message type /// /// - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public static Task Produce( this IProducer producer, StreamName stream, diff --git a/src/Core/src/Eventuous.Serialization.Json.Dynamic/DefaultEventSerializer.cs b/src/Core/src/Eventuous.Serialization.Json.Dynamic/DefaultEventSerializer.cs new file mode 100644 index 000000000..4ec488624 --- /dev/null +++ b/src/Core/src/Eventuous.Serialization.Json.Dynamic/DefaultEventSerializer.cs @@ -0,0 +1,48 @@ +// Copyright (C) Eventuous HQ OÜ. All rights reserved +// Licensed under the Apache License, Version 2.0. + +using System.Text.Json; +using static Eventuous.DeserializationResult; + +namespace Eventuous; + +[PublicAPI] +public class DefaultEventSerializer : IEventSerializer { + const string DynamicSerializationMessage = + "DefaultEventSerializer uses reflection-based System.Text.Json serialization. Use DefaultStaticEventSerializer with a JsonSerializerContext in trimmed or AOT applications."; + + readonly JsonSerializerOptions _options; + readonly ITypeMapper _typeMapper; + + [RequiresUnreferencedCode(DynamicSerializationMessage)] + [RequiresDynamicCode(DynamicSerializationMessage)] + public DefaultEventSerializer(JsonSerializerOptions options, ITypeMapper? typeMapper = null) { + _options = options; + _typeMapper = typeMapper ?? TypeMap.Instance; + + // Auto-register as default if none is set + EventSerializer.TrySetDefault(this); + } + + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "The constructor is annotated with RequiresUnreferencedCode, so an instance only exists if the caller acknowledged the requirement")] + [UnconditionalSuppressMessage("AOT", "IL3050", Justification = "The constructor is annotated with RequiresDynamicCode, so an instance only exists if the caller acknowledged the requirement")] + public DeserializationResult DeserializeEvent(ReadOnlySpan data, string eventType, string contentType) { + var typeMapped = _typeMapper.TryGetType(eventType, out var dataType); + + if (!typeMapped) return new FailedToDeserialize(DeserializationError.UnknownType); + if (contentType != ContentType) return new FailedToDeserialize(DeserializationError.ContentTypeMismatch); + + var deserialized = JsonSerializer.Deserialize(data, dataType!, _options); + + return deserialized != null + ? new SuccessfullyDeserialized(deserialized) + : new FailedToDeserialize(DeserializationError.PayloadEmpty); + } + + [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "The constructor is annotated with RequiresUnreferencedCode, so an instance only exists if the caller acknowledged the requirement")] + [UnconditionalSuppressMessage("AOT", "IL3050", Justification = "The constructor is annotated with RequiresDynamicCode, so an instance only exists if the caller acknowledged the requirement")] + public SerializationResult SerializeEvent(object evt) + => new(_typeMapper.GetTypeName(evt), ContentType, JsonSerializer.SerializeToUtf8Bytes(evt, _options)); + + public string ContentType { get; } = "application/json"; +} diff --git a/src/Core/src/Eventuous.Serialization.Json.Dynamic/Eventuous.Serialization.Json.Dynamic.csproj b/src/Core/src/Eventuous.Serialization.Json.Dynamic/Eventuous.Serialization.Json.Dynamic.csproj new file mode 100644 index 000000000..3b8be4ddc --- /dev/null +++ b/src/Core/src/Eventuous.Serialization.Json.Dynamic/Eventuous.Serialization.Json.Dynamic.csproj @@ -0,0 +1,10 @@ + + + Eventuous + + true + + + + + diff --git a/src/Core/src/Eventuous.Serialization/DefaultEventSerializer.cs b/src/Core/src/Eventuous.Serialization/DefaultEventSerializer.cs deleted file mode 100644 index 5922d44db..000000000 --- a/src/Core/src/Eventuous.Serialization/DefaultEventSerializer.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (C) Eventuous HQ OÜ. All rights reserved -// Licensed under the Apache License, Version 2.0. - -using System.Text.Json; -using static Eventuous.DeserializationResult; - -namespace Eventuous; - -[PublicAPI] -public class DefaultEventSerializer(JsonSerializerOptions options, ITypeMapper? typeMapper = null) : IEventSerializer { - static readonly JsonSerializerOptions Options = new(JsonSerializerDefaults.Web); - - public static IEventSerializer Instance { get; private set; } = new DefaultEventSerializer(Options); - - readonly ITypeMapper _typeMapper = typeMapper ?? TypeMap.Instance; - - public static void SetDefaultSerializer(IEventSerializer serializer) => Instance = serializer; - - [RequiresUnreferencedCode(IEventSerializer.SerializationUnreferencedCodeMessage)] - [RequiresDynamicCode(IEventSerializer.SerializationRequiresDynamicCodeMessage)] - public DeserializationResult DeserializeEvent(ReadOnlySpan data, string eventType, string contentType) { - var typeMapped = _typeMapper.TryGetType(eventType, out var dataType); - - if (!typeMapped) return new FailedToDeserialize(DeserializationError.UnknownType); - if (contentType != ContentType) return new FailedToDeserialize(DeserializationError.ContentTypeMismatch); - - var deserialized = JsonSerializer.Deserialize(data, dataType!, options); - - return deserialized != null - ? new SuccessfullyDeserialized(deserialized) - : new FailedToDeserialize(DeserializationError.PayloadEmpty); - } - - [RequiresUnreferencedCode(IEventSerializer.SerializationUnreferencedCodeMessage)] - [RequiresDynamicCode(IEventSerializer.SerializationRequiresDynamicCodeMessage)] - public SerializationResult SerializeEvent(object evt) - => new(_typeMapper.GetTypeName(evt), ContentType, JsonSerializer.SerializeToUtf8Bytes(evt, options)); - - public string ContentType { get; } = "application/json"; -} diff --git a/src/Core/src/Eventuous.Serialization/DefaultStaticEventSerializer.cs b/src/Core/src/Eventuous.Serialization/DefaultStaticEventSerializer.cs index 18b38a468..31dc927a3 100644 --- a/src/Core/src/Eventuous.Serialization/DefaultStaticEventSerializer.cs +++ b/src/Core/src/Eventuous.Serialization/DefaultStaticEventSerializer.cs @@ -11,8 +11,6 @@ namespace Eventuous; public class DefaultStaticEventSerializer(JsonSerializerContext context, ITypeMapper? typeMapper = null) : IEventSerializer { readonly ITypeMapper _typeMapper = typeMapper ?? TypeMap.Instance; - [UnconditionalSuppressMessage("Trimming", "IL2046", Justification = "This implementation is not using reflection.")] - [UnconditionalSuppressMessage("Trimming", "IL3051", Justification = "This implementation is not using reflection.")] public DeserializationResult DeserializeEvent(ReadOnlySpan data, string eventType, string contentType) { var typeMapped = _typeMapper.TryGetType(eventType, out var dataType); @@ -26,8 +24,6 @@ public DeserializationResult DeserializeEvent(ReadOnlySpan data, string ev : new FailedToDeserialize(DeserializationError.PayloadEmpty); } - [UnconditionalSuppressMessage("Trimming", "IL2046", Justification = "This implementation is not using reflection.")] - [UnconditionalSuppressMessage("Trimming", "IL3051", Justification = "This implementation is not using reflection.")] public SerializationResult SerializeEvent(object evt) => new(_typeMapper.GetTypeName(evt), ContentType, JsonSerializer.SerializeToUtf8Bytes(evt, evt.GetType(), context)); diff --git a/src/Core/src/Eventuous.Serialization/EventSerializer.cs b/src/Core/src/Eventuous.Serialization/EventSerializer.cs new file mode 100644 index 000000000..7d33f9c86 --- /dev/null +++ b/src/Core/src/Eventuous.Serialization/EventSerializer.cs @@ -0,0 +1,39 @@ +// Copyright (C) Eventuous HQ OÜ. All rights reserved +// Licensed under the Apache License, Version 2.0. + +namespace Eventuous; + +/// +/// Static holder for the default event serializer instance. +/// Must be configured before use — either via or DI registration. +/// For AOT applications, use with a . +/// +[PublicAPI] +public static class EventSerializer { + static IEventSerializer? _default; + + /// + /// Gets the default event serializer. Throws if not configured. + /// + public static IEventSerializer Default => _default + ?? throw new InvalidOperationException( + "No default event serializer configured. " + + "Call EventSerializer.SetDefault() at startup or register IEventSerializer in DI. " + + "For AOT, use DefaultStaticEventSerializer with a JsonSerializerContext."); + + /// + /// Sets the default event serializer instance. + /// + public static void SetDefault(IEventSerializer serializer) + => _default = serializer ?? throw new ArgumentNullException(nameof(serializer)); + + /// + /// Sets the default event serializer only if one has not already been configured. + /// Returns true if the default was set, false if it was already configured. + /// + public static bool TrySetDefault(IEventSerializer serializer) { + ArgumentNullException.ThrowIfNull(serializer); + + return Interlocked.CompareExchange(ref _default, serializer, null) == null; + } +} diff --git a/src/Core/src/Eventuous.Serialization/IEventSerializer.cs b/src/Core/src/Eventuous.Serialization/IEventSerializer.cs index 1b52eebf8..d8bc08865 100644 --- a/src/Core/src/Eventuous.Serialization/IEventSerializer.cs +++ b/src/Core/src/Eventuous.Serialization/IEventSerializer.cs @@ -4,19 +4,9 @@ namespace Eventuous; public interface IEventSerializer { - [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] - [RequiresDynamicCode(SerializationRequiresDynamicCodeMessage)] DeserializationResult DeserializeEvent(ReadOnlySpan data, string eventType, string contentType); - [RequiresUnreferencedCode(SerializationUnreferencedCodeMessage)] - [RequiresDynamicCode(SerializationRequiresDynamicCodeMessage)] SerializationResult SerializeEvent(object evt); - - internal const string SerializationUnreferencedCodeMessage = - "JSON serialization and deserialization might require types that cannot be statically analyzed. Use DefaultStaticEventSerializer with System.Text.Json source generation for native AOT applications."; - - internal const string SerializationRequiresDynamicCodeMessage = - "JSON serialization and deserialization might require types that cannot be statically analyzed and might need runtime code generation. Use DefaultStaticEventSerializer with System.Text.Json source generation for native AOT applications."; } public record SerializationResult(string EventType, string ContentType, byte[] Payload); diff --git a/src/Core/src/Eventuous.Subscriptions/Constants.cs b/src/Core/src/Eventuous.Subscriptions/Constants.cs deleted file mode 100644 index e726cd758..000000000 --- a/src/Core/src/Eventuous.Subscriptions/Constants.cs +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (C) Eventuous HQ OÜ. All rights reserved -// Licensed under the Apache License, Version 2.0. - -namespace Eventuous.Subscriptions; - -internal static class AttrConstants { - internal const string DynamicSerializationMessage = "Only works with AOT when using DefaultStaticEventSerializer"; -} diff --git a/src/Core/src/Eventuous.Subscriptions/EventSubscription.cs b/src/Core/src/Eventuous.Subscriptions/EventSubscription.cs index 443d69010..281dfc7e3 100644 --- a/src/Core/src/Eventuous.Subscriptions/EventSubscription.cs +++ b/src/Core/src/Eventuous.Subscriptions/EventSubscription.cs @@ -11,7 +11,6 @@ namespace Eventuous.Subscriptions; -using System.Diagnostics.CodeAnalysis; using Context; using Diagnostics; using Filters; @@ -44,7 +43,7 @@ protected EventSubscription( LoggerFactory = loggerFactory; Pipe = Ensure.NotNull(consumePipe); - EventSerializer = eventSerializer ?? DefaultEventSerializer.Instance; + EventSerializer = eventSerializer ?? Eventuous.EventSerializer.Default; Options = options; Log = Logger.CreateContext(options.SubscriptionId, loggerFactory); } @@ -54,8 +53,6 @@ protected EventSubscription( public string SubscriptionId => Options.SubscriptionId; - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] public async ValueTask Subscribe(OnSubscribed onSubscribed, OnDropped onDropped, CancellationToken cancellationToken) { if (IsRunning) return; @@ -152,8 +149,6 @@ protected async ValueTask Handler(IMessageConsumeContext context) { } } - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] protected object? DeserializeData(string eventContentType, string eventType, ReadOnlyMemory data, string stream, ulong position = 0) { if (data.IsEmpty) return null; @@ -184,15 +179,11 @@ protected async ValueTask Handler(IMessageConsumeContext context) { } // TODO: Passing the handler function would allow decoupling subscribers from handlers - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] protected abstract ValueTask Subscribe(CancellationToken cancellationToken); protected abstract ValueTask Unsubscribe(CancellationToken cancellationToken); [PublicAPI] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] protected virtual async Task Resubscribe(TimeSpan delay, CancellationToken cancellationToken) { await Task.Delay(delay, cancellationToken).NoContext(); @@ -213,8 +204,6 @@ protected virtual async Task Resubscribe(TimeSpan delay, CancellationToken cance } } - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] protected void Dropped(DropReason reason, Exception? exception) { if (!IsRunning) return; diff --git a/src/Core/src/Eventuous.Subscriptions/EventSubscriptionWithCheckpoint.cs b/src/Core/src/Eventuous.Subscriptions/EventSubscriptionWithCheckpoint.cs index 2e3bd9812..863991299 100644 --- a/src/Core/src/Eventuous.Subscriptions/EventSubscriptionWithCheckpoint.cs +++ b/src/Core/src/Eventuous.Subscriptions/EventSubscriptionWithCheckpoint.cs @@ -6,7 +6,6 @@ namespace Eventuous.Subscriptions; -using System.Diagnostics.CodeAnalysis; using Checkpoints; using Context; using Filters; @@ -53,8 +52,6 @@ EventPosition GetPositionFromContext(IMessageConsumeContext context) SubscriptionKind.Stream => EventPosition.FromContext(context) }; - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] protected async ValueTask HandleInternal(IMessageConsumeContext context) { try { Logger.Current = Log; @@ -76,8 +73,6 @@ protected async ValueTask HandleInternal(IMessageConsumeContext context) { /// that throw would silently kill the channel worker without triggering Dropped/Resubscribe. /// This wrapper catches the throw and calls Dropped instead. /// - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] ValueTask NackOnAsyncWorker(IMessageConsumeContext context, Exception exception) { try { return Nack(context, exception); @@ -133,8 +128,6 @@ protected async Task GetCheckpoint(CancellationToken cancellationTok return checkpoint; } - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] protected override async Task Resubscribe(TimeSpan delay, CancellationToken cancellationToken) { // Reset checkpoint state so the new run reads from the committed checkpoint, // not from LastProcessed (which may be ahead of the failed event). diff --git a/src/Core/src/Eventuous.Subscriptions/IMessageSubscription.cs b/src/Core/src/Eventuous.Subscriptions/IMessageSubscription.cs index df49fc6f0..190c189db 100644 --- a/src/Core/src/Eventuous.Subscriptions/IMessageSubscription.cs +++ b/src/Core/src/Eventuous.Subscriptions/IMessageSubscription.cs @@ -14,8 +14,6 @@ namespace Eventuous.Subscriptions; public interface IMessageSubscription { string SubscriptionId { get; } - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] ValueTask Subscribe(OnSubscribed onSubscribed, OnDropped onDropped, CancellationToken cancellationToken); ValueTask Unsubscribe(OnUnsubscribed onUnsubscribed, CancellationToken cancellationToken); diff --git a/src/Core/test/Eventuous.Tests.Persistence.Base/Eventuous.Tests.Persistence.Base.csproj b/src/Core/test/Eventuous.Tests.Persistence.Base/Eventuous.Tests.Persistence.Base.csproj index 0805456be..e7f6fe565 100644 --- a/src/Core/test/Eventuous.Tests.Persistence.Base/Eventuous.Tests.Persistence.Base.csproj +++ b/src/Core/test/Eventuous.Tests.Persistence.Base/Eventuous.Tests.Persistence.Base.csproj @@ -17,5 +17,6 @@ + \ No newline at end of file diff --git a/src/Core/test/Eventuous.Tests.Subscriptions.Base/Eventuous.Tests.Subscriptions.Base.csproj b/src/Core/test/Eventuous.Tests.Subscriptions.Base/Eventuous.Tests.Subscriptions.Base.csproj index 6647c4590..5bdf142bd 100644 --- a/src/Core/test/Eventuous.Tests.Subscriptions.Base/Eventuous.Tests.Subscriptions.Base.csproj +++ b/src/Core/test/Eventuous.Tests.Subscriptions.Base/Eventuous.Tests.Subscriptions.Base.csproj @@ -6,6 +6,7 @@ + diff --git a/src/Core/test/Eventuous.Tests.Subscriptions.Base/TestSetup.cs b/src/Core/test/Eventuous.Tests.Subscriptions.Base/TestSetup.cs new file mode 100644 index 000000000..c2edd8673 --- /dev/null +++ b/src/Core/test/Eventuous.Tests.Subscriptions.Base/TestSetup.cs @@ -0,0 +1,12 @@ +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Text.Json; + +namespace Eventuous.Tests.Subscriptions.Base; + +static class TestSetup { + [ModuleInitializer] + [SuppressMessage("Usage", "CA2255")] + internal static void Initialize() + => EventSerializer.SetDefault(new DefaultEventSerializer(new(JsonSerializerDefaults.Web))); +} diff --git a/src/Core/test/Eventuous.Tests.Subscriptions/Eventuous.Tests.Subscriptions.csproj b/src/Core/test/Eventuous.Tests.Subscriptions/Eventuous.Tests.Subscriptions.csproj index 522d87cd3..673f6ca15 100644 --- a/src/Core/test/Eventuous.Tests.Subscriptions/Eventuous.Tests.Subscriptions.csproj +++ b/src/Core/test/Eventuous.Tests.Subscriptions/Eventuous.Tests.Subscriptions.csproj @@ -7,6 +7,7 @@ + diff --git a/src/Core/test/Eventuous.Tests.Subscriptions/TestSetup.cs b/src/Core/test/Eventuous.Tests.Subscriptions/TestSetup.cs new file mode 100644 index 000000000..c48f06b1c --- /dev/null +++ b/src/Core/test/Eventuous.Tests.Subscriptions/TestSetup.cs @@ -0,0 +1,12 @@ +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Text.Json; + +namespace Eventuous.Tests.Subscriptions; + +static class TestSetup { + [ModuleInitializer] + [SuppressMessage("Usage", "CA2255")] + internal static void Initialize() + => EventSerializer.SetDefault(new DefaultEventSerializer(new(JsonSerializerDefaults.Web))); +} diff --git a/src/Experimental/src/ElasticPlayground/ElasticPlayground.csproj b/src/Experimental/src/ElasticPlayground/ElasticPlayground.csproj index 3bf2878d0..1853557a0 100644 --- a/src/Experimental/src/ElasticPlayground/ElasticPlayground.csproj +++ b/src/Experimental/src/ElasticPlayground/ElasticPlayground.csproj @@ -8,6 +8,7 @@ + diff --git a/src/Experimental/src/ElasticPlayground/Program.cs b/src/Experimental/src/ElasticPlayground/Program.cs index 44fb7f498..aff819327 100644 --- a/src/Experimental/src/ElasticPlayground/Program.cs +++ b/src/Experimental/src/ElasticPlayground/Program.cs @@ -26,7 +26,7 @@ var kurrentDBClientSettings = KurrentDBClientSettings.Create("esdb://localhost:2113?tls=false"); var kurrentDBClient = new KurrentDBClient(kurrentDBClientSettings); -DefaultEventSerializer.SetDefaultSerializer(new DefaultEventSerializer(options)); +EventSerializer.SetDefault(new DefaultEventSerializer(options)); // var elasticOnly = new ElasticOnly(client); // await elasticOnly.Execute(); diff --git a/src/Extensions/test/Eventuous.Sut.AspNetCore/Eventuous.Sut.AspNetCore.csproj b/src/Extensions/test/Eventuous.Sut.AspNetCore/Eventuous.Sut.AspNetCore.csproj index fc6727756..28c6664ed 100644 --- a/src/Extensions/test/Eventuous.Sut.AspNetCore/Eventuous.Sut.AspNetCore.csproj +++ b/src/Extensions/test/Eventuous.Sut.AspNetCore/Eventuous.Sut.AspNetCore.csproj @@ -9,6 +9,7 @@ + Analyzer false diff --git a/src/Extensions/test/Eventuous.Sut.AspNetCore/Program.cs b/src/Extensions/test/Eventuous.Sut.AspNetCore/Program.cs index beb858cb7..a2d93e4f2 100644 --- a/src/Extensions/test/Eventuous.Sut.AspNetCore/Program.cs +++ b/src/Extensions/test/Eventuous.Sut.AspNetCore/Program.cs @@ -5,7 +5,7 @@ using Microsoft.AspNetCore.Http.Json; using BookingService = Eventuous.Sut.AspNetCore.BookingService; -DefaultEventSerializer.SetDefaultSerializer(new DefaultEventSerializer(TestPrimitives.DefaultOptions)); +EventSerializer.SetDefault(new DefaultEventSerializer(TestPrimitives.DefaultOptions)); var builder = WebApplication.CreateBuilder(args); builder.Services.AddCommandService(); diff --git a/src/Gateway/test/Eventuous.Tests.Gateway/Eventuous.Tests.Gateway.csproj b/src/Gateway/test/Eventuous.Tests.Gateway/Eventuous.Tests.Gateway.csproj index c02634dd2..83c908e7e 100644 --- a/src/Gateway/test/Eventuous.Tests.Gateway/Eventuous.Tests.Gateway.csproj +++ b/src/Gateway/test/Eventuous.Tests.Gateway/Eventuous.Tests.Gateway.csproj @@ -5,6 +5,7 @@ + diff --git a/src/Gateway/test/Eventuous.Tests.Gateway/TestSetup.cs b/src/Gateway/test/Eventuous.Tests.Gateway/TestSetup.cs new file mode 100644 index 000000000..9d47ce94c --- /dev/null +++ b/src/Gateway/test/Eventuous.Tests.Gateway/TestSetup.cs @@ -0,0 +1,12 @@ +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Text.Json; + +namespace Eventuous.Tests.Gateway; + +static class TestSetup { + [ModuleInitializer] + [SuppressMessage("Usage", "CA2255")] + internal static void Initialize() + => EventSerializer.SetDefault(new DefaultEventSerializer(new(JsonSerializerDefaults.Web))); +} diff --git a/src/GooglePubSub/src/Eventuous.GooglePubSub/Producers/GooglePubSubProducer.cs b/src/GooglePubSub/src/Eventuous.GooglePubSub/Producers/GooglePubSubProducer.cs index 7fb8d6779..0304bc5f0 100644 --- a/src/GooglePubSub/src/Eventuous.GooglePubSub/Producers/GooglePubSubProducer.cs +++ b/src/GooglePubSub/src/Eventuous.GooglePubSub/Producers/GooglePubSubProducer.cs @@ -42,7 +42,7 @@ public GooglePubSubProducer( public GooglePubSubProducer(PubSubProducerOptions options, IEventSerializer? serializer = null, ILogger? log = null) : base(TracingOptions) { Ensure.NotNull(options); - _serializer = serializer ?? DefaultEventSerializer.Instance; + _serializer = serializer ?? EventSerializer.Default; _clientCache = new(options, log); _attributes = options.Attributes; _log = log; diff --git a/src/Kafka/src/Eventuous.Kafka/Producers/KafkaBasicProducer.cs b/src/Kafka/src/Eventuous.Kafka/Producers/KafkaBasicProducer.cs index b6dbf82e5..6a0d00500 100644 --- a/src/Kafka/src/Eventuous.Kafka/Producers/KafkaBasicProducer.cs +++ b/src/Kafka/src/Eventuous.Kafka/Producers/KafkaBasicProducer.cs @@ -19,7 +19,7 @@ public KafkaBasicProducer(KafkaProducerOptions options, IEventSerializer? serial : base(TracingOptions) { _producerWithKey = new ProducerBuilder(options.ProducerConfig).Build(); _producerWithoutKey = new DependentProducerBuilder(_producerWithKey.Handle).Build(); - _serializer = serializer ?? DefaultEventSerializer.Instance; + _serializer = serializer ?? EventSerializer.Default; } static readonly ProducerTracingOptions TracingOptions = new() { diff --git a/src/Kafka/test/Eventuous.Tests.Kafka/BasicProducerTests.cs b/src/Kafka/test/Eventuous.Tests.Kafka/BasicProducerTests.cs index 9ccda44ec..b7cc44b50 100644 --- a/src/Kafka/test/Eventuous.Tests.Kafka/BasicProducerTests.cs +++ b/src/Kafka/test/Eventuous.Tests.Kafka/BasicProducerTests.cs @@ -70,7 +70,7 @@ async Task Consume(IConsumer c, CancellationToken ct) { var messageType = meta[KafkaHeaderKeys.MessageTypeHeader] as string; var contentType = meta[KafkaHeaderKeys.ContentTypeHeader] as string; - var result = DefaultEventSerializer.Instance.DeserializeEvent(msg.Message.Value, messageType!, contentType!) as SuccessfullyDeserialized; + var result = EventSerializer.Default.DeserializeEvent(msg.Message.Value, messageType!, contentType!) as SuccessfullyDeserialized; var evt = (result!.Payload as TestEvent)!; TestContext.Current?.OutputWriter.WriteLine($"Consumed {evt}"); diff --git a/src/KurrentDB/src/Eventuous.KurrentDB/Constants.cs b/src/KurrentDB/src/Eventuous.KurrentDB/Constants.cs deleted file mode 100644 index 06eef81ad..000000000 --- a/src/KurrentDB/src/Eventuous.KurrentDB/Constants.cs +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (C) Eventuous HQ OÜ. All rights reserved -// Licensed under the Apache License, Version 2.0. - -namespace Eventuous.KurrentDB; - -internal static class AttrConstants { - internal const string DynamicSerializationMessage = "Only works with AOT when using DefaultStaticEventSerializer"; -} diff --git a/src/KurrentDB/src/Eventuous.KurrentDB/KurrentDBEventStore.cs b/src/KurrentDB/src/Eventuous.KurrentDB/KurrentDBEventStore.cs index 5deced054..d8cf4a269 100644 --- a/src/KurrentDB/src/Eventuous.KurrentDB/KurrentDBEventStore.cs +++ b/src/KurrentDB/src/Eventuous.KurrentDB/KurrentDBEventStore.cs @@ -79,7 +79,7 @@ public KurrentDBEventStore( ILogger? logger = null ) { _client = Ensure.NotNull(client); - _serializer = serializer ?? DefaultEventSerializer.Instance; + _serializer = serializer ?? EventSerializer.Default; _metaSerializer = metaSerializer ?? DefaultMetadataSerializer.Instance; _logger = logger ?? NullLogger.Instance; } @@ -110,8 +110,6 @@ public async Task StreamExists(StreamName stream, CancellationToken cancel } /// - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public Task AppendEvents( StreamName stream, ExpectedStreamVersion expectedVersion, @@ -140,8 +138,6 @@ public Task AppendEvents( } ); - [RequiresDynamicCode("Calls Eventuous.IEventSerializer.SerializeEvent(Object)")] - [RequiresUnreferencedCode("Calls Eventuous.IEventSerializer.SerializeEvent(Object)")] EventData ToEventData(NewStreamEvent streamEvent) { var (eventType, contentType, payload) = _serializer.SerializeEvent(streamEvent.Payload!); @@ -156,8 +152,6 @@ EventData ToEventData(NewStreamEvent streamEvent) { } /// - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public Task AppendEvents( IReadOnlyCollection appends, CancellationToken cancellationToken = default @@ -207,8 +201,6 @@ static async IAsyncEnumerable ToAsyncEnumerable(IEnumerable } } - [RequiresDynamicCode("Calls Eventuous.IEventSerializer.SerializeEvent(Object)")] - [RequiresUnreferencedCode("Calls Eventuous.IEventSerializer.SerializeEvent(Object)")] EventData ToEventData(NewStreamEvent streamEvent) { var (eventType, contentType, payload) = _serializer.SerializeEvent(streamEvent.Payload!); @@ -223,8 +215,6 @@ EventData ToEventData(NewStreamEvent streamEvent) { } /// - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public async IAsyncEnumerable ReadEvents(StreamName stream, StreamReadPosition start, int count, [EnumeratorCancellation] CancellationToken cancellationToken = default) { var read = _client.ReadStreamAsync(Direction.Forwards, stream, start.AsStreamPosition(), count, cancellationToken: cancellationToken); @@ -244,8 +234,6 @@ public async IAsyncEnumerable ReadEvents(StreamName stream, StreamR } /// - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] public async IAsyncEnumerable ReadEventsBackwards(StreamName stream, StreamReadPosition start, int count, [EnumeratorCancellation] CancellationToken cancellationToken = default) { var read = _client.ReadStreamAsync( Direction.Backwards, @@ -334,8 +322,6 @@ static StreamState ToStreamState(ExpectedStreamVersion version) : StreamState.StreamRevision((ulong)version.Value); [MethodImpl(MethodImplOptions.AggressiveInlining)] - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] StreamEvent? ToStreamEvent(ResolvedEvent resolvedEvent) { var deserialized = _serializer.DeserializeEvent( resolvedEvent.Event.Data.Span, @@ -375,8 +361,6 @@ StreamEvent AsStreamEvent(object payload) ); } - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] StreamEvent[] ToStreamEvents(ResolvedEvent[] resolvedEvents) => resolvedEvents .Select(ToStreamEvent) diff --git a/src/KurrentDB/src/Eventuous.KurrentDB/Producers/KurrentDBProducer.cs b/src/KurrentDB/src/Eventuous.KurrentDB/Producers/KurrentDBProducer.cs index fda3263cb..8399485fd 100644 --- a/src/KurrentDB/src/Eventuous.KurrentDB/Producers/KurrentDBProducer.cs +++ b/src/KurrentDB/src/Eventuous.KurrentDB/Producers/KurrentDBProducer.cs @@ -25,7 +25,7 @@ public class KurrentDBProducer : BaseProducer { public KurrentDBProducer(KurrentDBClient client, IEventSerializer? serializer = null, IMetadataSerializer? metaSerializer = null) : base(TracingOptions) { _client = Ensure.NotNull(client); - _serializer = serializer ?? DefaultEventSerializer.Instance; + _serializer = serializer ?? EventSerializer.Default; _metaSerializer = metaSerializer ?? DefaultMetadataSerializer.Instance; } @@ -51,8 +51,6 @@ public KurrentDBProducer(KurrentDBClientSettings clientSettings, IEventSerialize /// Batch of messages /// Options for the produce operation /// - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] protected override async Task ProduceMessages( StreamName stream, IEnumerable messages, @@ -89,8 +87,6 @@ await chunkMessages } } - [RequiresUnreferencedCode("Calls Eventuous.IEventSerializer.SerializeEvent(Object)")] - [RequiresDynamicCode("Calls Eventuous.IEventSerializer.SerializeEvent(Object)")] EventData CreateMessage(ProducedMessage message, bool setMessageType) { var msg = Ensure.NotNull(message.Message); var (eventType, contentType, payload) = _serializer.SerializeEvent(msg); diff --git a/src/KurrentDB/src/Eventuous.KurrentDB/Subscriptions/AllStreamSubscription.cs b/src/KurrentDB/src/Eventuous.KurrentDB/Subscriptions/AllStreamSubscription.cs index 64c324ab6..5ccd34c61 100644 --- a/src/KurrentDB/src/Eventuous.KurrentDB/Subscriptions/AllStreamSubscription.cs +++ b/src/KurrentDB/src/Eventuous.KurrentDB/Subscriptions/AllStreamSubscription.cs @@ -89,8 +89,6 @@ public AllStreamSubscription( /// Starts the subscription /// /// - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] protected override async ValueTask Subscribe(CancellationToken cancellationToken) { var filterOptions = new SubscriptionFilterOptions(Options.EventFilter ?? EventTypeFilter.ExcludeSystemEvents(), Options.CheckpointInterval); @@ -136,8 +134,6 @@ protected override async ValueTask Subscribe(CancellationToken cancellationToken /// handlers as before, plus the caught-up notification, which the callback-based client API /// silently discards. The message-based API is used precisely to observe that notification. /// - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] async Task PumpMessages( KurrentDBClient.StreamSubscriptionResult subscription, IAsyncEnumerator messages, @@ -250,8 +246,6 @@ protected override async ValueTask Unsubscribe(CancellationToken cancellationTok /// static ulong GetContextPosition(ResolvedEvent re) => (re.OriginalPosition ?? re.OriginalEvent.Position).CommitPosition; - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] MessageConsumeContext CreateContext(ResolvedEvent re, CancellationToken cancellationToken) { var evt = DeserializeData( re.Event.ContentType, @@ -287,8 +281,6 @@ MessageConsumeContext CreateContext(ResolvedEvent re, CancellationToken cancella /// everything since then, and consumers comparing the checkpoint to the $all head see a phantom, /// never-closing lag. /// - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] Task HandleCheckpointReached(global::KurrentDB.Client.Position position, CancellationToken cancellationToken) { var context = new MessageConsumeContext( position.CommitPosition.ToString(), diff --git a/src/KurrentDB/src/Eventuous.KurrentDB/Subscriptions/PersistentSubscriptionBase.cs b/src/KurrentDB/src/Eventuous.KurrentDB/Subscriptions/PersistentSubscriptionBase.cs index c8506018b..303d1efb5 100644 --- a/src/KurrentDB/src/Eventuous.KurrentDB/Subscriptions/PersistentSubscriptionBase.cs +++ b/src/KurrentDB/src/Eventuous.KurrentDB/Subscriptions/PersistentSubscriptionBase.cs @@ -116,8 +116,6 @@ protected PersistentSubscriptionBase( /// Subscribe to a persistent subscription /// /// - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] protected override async ValueTask Subscribe(CancellationToken cancellationToken) { var settings = Options.SubscriptionSettings ?? new PersistentSubscriptionSettings(Options.ResolveLinkTos); @@ -196,8 +194,6 @@ async ValueTask Nack(MessageConsumeContext ctx, Exception exception) { await _handleEventProcessingFailure(Client, subscription, re, exception).NoContext(); } - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] MessageConsumeContext CreateContext(ResolvedEvent re, CancellationToken cancellationToken) { var evt = DeserializeData( re.Event.ContentType, diff --git a/src/KurrentDB/src/Eventuous.KurrentDB/Subscriptions/StreamSubscription.cs b/src/KurrentDB/src/Eventuous.KurrentDB/Subscriptions/StreamSubscription.cs index d9029e823..9254e5e4b 100644 --- a/src/KurrentDB/src/Eventuous.KurrentDB/Subscriptions/StreamSubscription.cs +++ b/src/KurrentDB/src/Eventuous.KurrentDB/Subscriptions/StreamSubscription.cs @@ -86,8 +86,6 @@ public StreamSubscription( /// Starts a catch-up subscription /// /// - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] protected override async ValueTask Subscribe(CancellationToken cancellationToken) { var (_, position) = await GetCheckpoint(cancellationToken).NoContext(); @@ -128,8 +126,6 @@ void HandleDrop(global::KurrentDB.Client.StreamSubscription _, SubscriptionDropp => Dropped(KurrentDBMappings.AsDropReason(reason), ex); } - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] MessageConsumeContext CreateContext(ResolvedEvent re, CancellationToken cancellationToken) { var evt = DeserializeData( re.Event.ContentType, diff --git a/src/KurrentDB/test/Eventuous.Tests.KurrentDB/Subscriptions/CustomDependenciesTests.cs b/src/KurrentDB/test/Eventuous.Tests.KurrentDB/Subscriptions/CustomDependenciesTests.cs index 2d4b0edea..33b36317b 100644 --- a/src/KurrentDB/test/Eventuous.Tests.KurrentDB/Subscriptions/CustomDependenciesTests.cs +++ b/src/KurrentDB/test/Eventuous.Tests.KurrentDB/Subscriptions/CustomDependenciesTests.cs @@ -106,7 +106,7 @@ public ValueTask StoreCheckpoint(Checkpoint checkpoint, bool force, class TestSerializer : IEventSerializer { public DeserializationResult DeserializeEvent(ReadOnlySpan data, string eventType, string contentType) { - var result = DefaultEventSerializer.Instance.DeserializeEvent(data, eventType, contentType); + var result = EventSerializer.Default.DeserializeEvent(data, eventType, contentType); if (result is not DeserializationResult.SuccessfullyDeserialized { Payload: var evt }) { return result; diff --git a/src/Mongo/test/Eventuous.Tests.Projections.MongoDB/Eventuous.Tests.Projections.MongoDB.csproj b/src/Mongo/test/Eventuous.Tests.Projections.MongoDB/Eventuous.Tests.Projections.MongoDB.csproj index ea0cab941..5aa7fd95a 100644 --- a/src/Mongo/test/Eventuous.Tests.Projections.MongoDB/Eventuous.Tests.Projections.MongoDB.csproj +++ b/src/Mongo/test/Eventuous.Tests.Projections.MongoDB/Eventuous.Tests.Projections.MongoDB.csproj @@ -11,6 +11,7 @@ + diff --git a/src/Mongo/test/Eventuous.Tests.Projections.MongoDB/Fixtures/IntegrationFixture.cs b/src/Mongo/test/Eventuous.Tests.Projections.MongoDB/Fixtures/IntegrationFixture.cs index fa4c755a3..0c8f0e550 100644 --- a/src/Mongo/test/Eventuous.Tests.Projections.MongoDB/Fixtures/IntegrationFixture.cs +++ b/src/Mongo/test/Eventuous.Tests.Projections.MongoDB/Fixtures/IntegrationFixture.cs @@ -26,7 +26,7 @@ public Task AppendEvent(StreamName streamName, object evt, E ); static IntegrationFixture() { - DefaultEventSerializer.SetDefaultSerializer(Serializer); + EventSerializer.SetDefault(Serializer); NodaTimeSerializers.Register(); } diff --git a/src/RabbitMq/src/Eventuous.RabbitMq/Constants.cs b/src/RabbitMq/src/Eventuous.RabbitMq/Constants.cs deleted file mode 100644 index 477d5cbd2..000000000 --- a/src/RabbitMq/src/Eventuous.RabbitMq/Constants.cs +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (C) Eventuous HQ OÜ. All rights reserved -// Licensed under the Apache License, Version 2.0. - -namespace Eventuous.RabbitMq; - -internal static class AttrConstants { - internal const string DynamicSerializationMessage = "Only works with AOT when using DefaultStaticEventSerializer"; -} diff --git a/src/RabbitMq/src/Eventuous.RabbitMq/Producers/RabbitMqProducer.cs b/src/RabbitMq/src/Eventuous.RabbitMq/Producers/RabbitMqProducer.cs index 4f9bcd880..275d62840 100644 --- a/src/RabbitMq/src/Eventuous.RabbitMq/Producers/RabbitMqProducer.cs +++ b/src/RabbitMq/src/Eventuous.RabbitMq/Producers/RabbitMqProducer.cs @@ -40,7 +40,7 @@ public RabbitMqProducer( : base(TracingOptions) { _log = log; _options = options; - _serializer = serializer ?? DefaultEventSerializer.Instance; + _serializer = serializer ?? EventSerializer.Default; _connectionFactory = Ensure.NotNull(connectionFactory); _exchangeCache = new(_log); } @@ -60,8 +60,6 @@ public Task StartAsync(CancellationToken cancellationToken = default) { ProduceOperation = "publish" }; - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] protected override async Task ProduceMessages( StreamName stream, IEnumerable messages, @@ -96,8 +94,6 @@ await failed .NoContext(); } - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] void Publish(string stream, ProducedMessage message, RabbitMqProduceOptions? options) { if (_channel == null) throw new InvalidOperationException("Producer hasn't been initialized, call Initialize"); diff --git a/src/RabbitMq/src/Eventuous.RabbitMq/Subscriptions/RabbitMqSubscription.cs b/src/RabbitMq/src/Eventuous.RabbitMq/Subscriptions/RabbitMqSubscription.cs index df39635c7..1b2bd7379 100644 --- a/src/RabbitMq/src/Eventuous.RabbitMq/Subscriptions/RabbitMqSubscription.cs +++ b/src/RabbitMq/src/Eventuous.RabbitMq/Subscriptions/RabbitMqSubscription.cs @@ -93,8 +93,6 @@ public RabbitMqSubscription( eventSerializer ) { } - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] protected override ValueTask Subscribe(CancellationToken cancellationToken) { var exchange = Ensure.NotEmptyString(Options.Exchange); @@ -142,8 +140,6 @@ protected override ValueTask Subscribe(CancellationToken cancellationToken) { const string ReceivedMessageKey = "receivedMessage"; - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] async Task HandleReceived(object sender, BasicDeliverEventArgs received) { Logger.Current = Log; @@ -172,8 +168,6 @@ ValueTask Nack(IMessageConsumeContext ctx, Exception exception) { return default; } - [RequiresUnreferencedCode(AttrConstants.DynamicSerializationMessage)] - [RequiresDynamicCode(AttrConstants.DynamicSerializationMessage)] MessageConsumeContext CreateContext(object sender, BasicDeliverEventArgs received) { var evt = DeserializeData(received.BasicProperties.ContentType, received.BasicProperties.Type, received.Body, received.Exchange); diff --git a/src/Redis/src/Eventuous.Redis/RedisStore.cs b/src/Redis/src/Eventuous.Redis/RedisStore.cs index 7a9cd2f23..a4a733693 100644 --- a/src/Redis/src/Eventuous.Redis/RedisStore.cs +++ b/src/Redis/src/Eventuous.Redis/RedisStore.cs @@ -29,7 +29,7 @@ public RedisStore( IEventSerializer? serializer = null, IMetadataSerializer? metaSerializer = null ) { - _serializer = serializer ?? DefaultEventSerializer.Instance; + _serializer = serializer ?? EventSerializer.Default; _metaSerializer = metaSerializer ?? DefaultMetadataSerializer.Instance; _getDatabase = Ensure.NotNull(getDatabase, "Connection factory"); } diff --git a/src/Redis/test/Eventuous.Tests.Redis/Eventuous.Tests.Redis.csproj b/src/Redis/test/Eventuous.Tests.Redis/Eventuous.Tests.Redis.csproj index 78daa2ab3..afd7d48da 100644 --- a/src/Redis/test/Eventuous.Tests.Redis/Eventuous.Tests.Redis.csproj +++ b/src/Redis/test/Eventuous.Tests.Redis/Eventuous.Tests.Redis.csproj @@ -16,5 +16,6 @@ + diff --git a/src/Redis/test/Eventuous.Tests.Redis/Fixtures/IntegrationFixture.cs b/src/Redis/test/Eventuous.Tests.Redis/Fixtures/IntegrationFixture.cs index a4600945d..4e0ec7ea5 100644 --- a/src/Redis/test/Eventuous.Tests.Redis/Fixtures/IntegrationFixture.cs +++ b/src/Redis/test/Eventuous.Tests.Redis/Fixtures/IntegrationFixture.cs @@ -18,7 +18,7 @@ public sealed class IntegrationFixture : IAsyncInitializer, IAsyncDisposable { IEventSerializer Serializer { get; } = new DefaultEventSerializer(TestPrimitives.DefaultOptions); - public IntegrationFixture() => DefaultEventSerializer.SetDefaultSerializer(Serializer); + public IntegrationFixture() => EventSerializer.SetDefault(Serializer); public async Task InitializeAsync() { _redisContainer = new RedisBuilder().WithImage("redis:7.0.12-alpine").Build(); diff --git a/src/Relational/src/Eventuous.Sql.Base/Constants.cs b/src/Relational/src/Eventuous.Sql.Base/Constants.cs deleted file mode 100644 index 932f86c6f..000000000 --- a/src/Relational/src/Eventuous.Sql.Base/Constants.cs +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (C) Eventuous HQ OÜ. All rights reserved -// Licensed under the Apache License, Version 2.0. - -namespace Eventuous.Sql.Base; - -internal static class Constants { - internal const string DynamicSerializationMessage = "Only works with AOT when using DefaultStaticEventSerializer"; -} diff --git a/src/Relational/src/Eventuous.Sql.Base/Producers/UniversalProducer.cs b/src/Relational/src/Eventuous.Sql.Base/Producers/UniversalProducer.cs index 66946706e..efe2877e8 100644 --- a/src/Relational/src/Eventuous.Sql.Base/Producers/UniversalProducer.cs +++ b/src/Relational/src/Eventuous.Sql.Base/Producers/UniversalProducer.cs @@ -11,8 +11,6 @@ namespace Eventuous.Sql.Base.Producers; /// public class UniversalProducer(IEventStore store) : IProducer { /// - [RequiresDynamicCode(Constants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(Constants.DynamicSerializationMessage)] public async Task Produce(StreamName stream, IEnumerable messages, CancellationToken cancellationToken = default) { var events = messages.Select(ToStreamEvent).ToList(); await store.AppendEvents(stream, ExpectedStreamVersion.Any, events, cancellationToken); diff --git a/src/Relational/src/Eventuous.Sql.Base/SqlEventStoreBase.cs b/src/Relational/src/Eventuous.Sql.Base/SqlEventStoreBase.cs index 552ae7f28..8f2a41d21 100644 --- a/src/Relational/src/Eventuous.Sql.Base/SqlEventStoreBase.cs +++ b/src/Relational/src/Eventuous.Sql.Base/SqlEventStoreBase.cs @@ -22,7 +22,7 @@ public abstract class SqlEventStoreBase(IEventSeriali /// /// Message serializer instance /// - protected IEventSerializer Serializer { get; } = serializer ?? DefaultEventSerializer.Instance; + protected IEventSerializer Serializer { get; } = serializer ?? EventSerializer.Default; /// /// Metadata serializer instance @@ -98,8 +98,6 @@ StreamTruncatePosition position ); /// - [RequiresDynamicCode(Constants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(Constants.DynamicSerializationMessage)] public async IAsyncEnumerable ReadEvents(StreamName stream, StreamReadPosition start, int count, [EnumeratorCancellation] CancellationToken cancellationToken) { if (count <= 0 || start == StreamReadPosition.End) yield break; @@ -109,8 +107,6 @@ public async IAsyncEnumerable ReadEvents(StreamName stream, StreamR } /// - [RequiresDynamicCode(Constants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(Constants.DynamicSerializationMessage)] public async IAsyncEnumerable ReadEventsBackwards(StreamName stream, StreamReadPosition start, int count, [EnumeratorCancellation] CancellationToken cancellationToken) { if (count <= 0) yield break; @@ -119,8 +115,6 @@ public async IAsyncEnumerable ReadEventsBackwards(StreamName stream foreach (var evt in events) yield return evt; } - [RequiresDynamicCode("Calls Eventuous.Sql.Base.SqlEventStoreBase.ToStreamEvent(PersistedEvent)")] - [RequiresUnreferencedCode("Calls Eventuous.Sql.Base.SqlEventStoreBase.ToStreamEvent(PersistedEvent)")] async Task ReadInternal(StreamName stream, StreamReadPosition start, int count, CancellationToken cancellationToken) { await using var connection = await OpenConnection(cancellationToken).NoContext(); await using var cmd = GetReadCommand(connection, stream, start, count); @@ -128,8 +122,6 @@ async Task ReadInternal(StreamName stream, StreamReadPosition sta return await ReadFromCommand(cmd, stream, cancellationToken).NoContext(); } - [RequiresDynamicCode("Calls Eventuous.Sql.Base.SqlEventStoreBase.ToStreamEvent(PersistedEvent)")] - [RequiresUnreferencedCode("Calls Eventuous.Sql.Base.SqlEventStoreBase.ToStreamEvent(PersistedEvent)")] async Task ReadInternalBackwards(StreamName stream, StreamReadPosition start, int count, CancellationToken cancellationToken) { await using var connection = await OpenConnection(cancellationToken).NoContext(); await using var cmd = GetReadBackwardsCommand(connection, stream, start, count); @@ -137,8 +129,6 @@ async Task ReadInternalBackwards(StreamName stream, StreamReadPos return await ReadFromCommand(cmd, stream, cancellationToken).NoContext(); } - [RequiresDynamicCode("Calls Eventuous.Sql.Base.SqlEventStoreBase.ToStreamEvent(PersistedEvent)")] - [RequiresUnreferencedCode("Calls Eventuous.Sql.Base.SqlEventStoreBase.ToStreamEvent(PersistedEvent)")] async Task ReadFromCommand(DbCommand cmd, StreamName stream, CancellationToken cancellationToken) { try { await using var reader = await cmd.ExecuteReaderAsync(cancellationToken).NoContext(); @@ -153,8 +143,6 @@ async Task ReadFromCommand(DbCommand cmd, StreamName stream, Canc } } - [RequiresDynamicCode("Calls Eventuous.IEventSerializer.DeserializeEvent(ReadOnlySpan, String, String)")] - [RequiresUnreferencedCode("Calls Eventuous.IEventSerializer.DeserializeEvent(ReadOnlySpan, String, String)")] StreamEvent ToStreamEvent(PersistedEvent evt) { var deserialized = Serializer.DeserializeEvent(Encoding.UTF8.GetBytes(evt.JsonData), evt.MessageType, ContentType); @@ -170,8 +158,6 @@ StreamEvent ToStreamEvent(PersistedEvent evt) { } /// - [RequiresDynamicCode(Constants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(Constants.DynamicSerializationMessage)] public virtual async Task AppendEvents( StreamName stream, ExpectedStreamVersion expectedVersion, @@ -202,8 +188,6 @@ CancellationToken cancellationToken throw IsConflict(e) ? new AppendToStreamException(stream, e) : e; } - [RequiresUnreferencedCode("Calls Eventuous.IEventSerializer.SerializeEvent(Object)")] - [RequiresDynamicCode("Calls Eventuous.IEventSerializer.SerializeEvent(Object)")] NewPersistedEvent Convert(NewStreamEvent evt) { var data = Serializer.SerializeEvent(evt.Payload!); var meta = MetaSerializer.Serialize(evt.Metadata); @@ -215,8 +199,6 @@ NewPersistedEvent Convert(NewStreamEvent evt) { } /// - [RequiresDynamicCode(Constants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(Constants.DynamicSerializationMessage)] public virtual async Task AppendEvents(IReadOnlyCollection appends, CancellationToken cancellationToken) { if (appends.Count == 0) return []; @@ -249,8 +231,6 @@ public virtual async Task AppendEvents(IReadOnlyCollection throw IsConflict(e) ? new AppendToStreamException(streamNames, e) : e; } - [RequiresUnreferencedCode("Calls Eventuous.IEventSerializer.SerializeEvent(Object)")] - [RequiresDynamicCode("Calls Eventuous.IEventSerializer.SerializeEvent(Object)")] NewPersistedEvent Convert(NewStreamEvent evt) { var data = Serializer.SerializeEvent(evt.Payload!); var meta = MetaSerializer.Serialize(evt.Metadata); diff --git a/src/Relational/src/Eventuous.Sql.Base/Subscriptions/SqlSubscriptionBase.cs b/src/Relational/src/Eventuous.Sql.Base/Subscriptions/SqlSubscriptionBase.cs index 343e44965..00b968baa 100644 --- a/src/Relational/src/Eventuous.Sql.Base/Subscriptions/SqlSubscriptionBase.cs +++ b/src/Relational/src/Eventuous.Sql.Base/Subscriptions/SqlSubscriptionBase.cs @@ -76,8 +76,6 @@ public abstract class SqlSubscriptionBase( private record DetectedGap(long Position, DateTime FirstSeen); - [RequiresUnreferencedCode("Calls ExecutePollCycle()")] - [RequiresDynamicCode("Calls ExecutePollCycle()")] async Task PollingQuery(ulong? position, CancellationToken cancellationToken) { var start = position.HasValue ? (long)position : -1; @@ -94,8 +92,6 @@ async Task PollingQuery(ulong? position, CancellationToken cancellationToken) { return; - [RequiresUnreferencedCode("Calls Eventuous.Sql.Base.Subscriptions.SqlSubscriptionBase.ToConsumeContext(PersistedEvent, CancellationToken)")] - [RequiresDynamicCode("Calls Eventuous.Sql.Base.Subscriptions.SqlSubscriptionBase.ToConsumeContext(PersistedEvent, CancellationToken)")] async Task Poll() { try { await using var connection = await OpenConnection(cancellationToken).NoContext(); @@ -153,8 +149,6 @@ async Task Poll() { } } - [RequiresDynamicCode("Calls Poll()")] - [RequiresUnreferencedCode("Calls Poll()")] async Task ExecutePollCycle() { while (!cancellationToken.IsCancellationRequested) { var result = await Poll().NoContext(); @@ -208,8 +202,6 @@ async Task ExecutePollCycle() { /// Starts the subscription /// /// - [RequiresDynamicCode(Constants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(Constants.DynamicSerializationMessage)] protected override async ValueTask Subscribe(CancellationToken cancellationToken) { await BeforeSubscribe(cancellationToken).NoContext(); var (_, position) = await GetCheckpoint(cancellationToken).NoContext(); @@ -250,8 +242,6 @@ protected override async ValueTask Unsubscribe(CancellationToken cancellationTok SubscriptionKind.Stream => evt.StreamPosition }; - [RequiresDynamicCode(Constants.DynamicSerializationMessage)] - [RequiresUnreferencedCode(Constants.DynamicSerializationMessage)] MessageConsumeContext ToConsumeContext(PersistedEvent evt, CancellationToken cancellationToken) { Logger.Current = Log; diff --git a/src/SignalR/src/Eventuous.SignalR.Client/SignalRSubscriptionClient.cs b/src/SignalR/src/Eventuous.SignalR.Client/SignalRSubscriptionClient.cs index 751911c50..4329bd38a 100644 --- a/src/SignalR/src/Eventuous.SignalR.Client/SignalRSubscriptionClient.cs +++ b/src/SignalR/src/Eventuous.SignalR.Client/SignalRSubscriptionClient.cs @@ -81,7 +81,7 @@ public async Task UnsubscribeAsync(string stream) { } } - internal IEventSerializer GetSerializer() => _options.Serializer ?? DefaultEventSerializer.Instance; + internal IEventSerializer GetSerializer() => _options.Serializer ?? EventSerializer.Default; internal bool TracingEnabled => _options.EnableTracing; diff --git a/src/SignalR/src/Eventuous.SignalR.Client/SignalRSubscriptionClientOptions.cs b/src/SignalR/src/Eventuous.SignalR.Client/SignalRSubscriptionClientOptions.cs index 129dbec31..e7dd0f92f 100644 --- a/src/SignalR/src/Eventuous.SignalR.Client/SignalRSubscriptionClientOptions.cs +++ b/src/SignalR/src/Eventuous.SignalR.Client/SignalRSubscriptionClientOptions.cs @@ -8,7 +8,7 @@ namespace Eventuous.SignalR.Client; /// public class SignalRSubscriptionClientOptions { /// - /// Optional event serializer. When not set, is used. + /// Optional event serializer. When not set, is used. /// public IEventSerializer? Serializer { get; set; } diff --git a/src/SignalR/src/Eventuous.SignalR.Server/SignalRProducer.cs b/src/SignalR/src/Eventuous.SignalR.Server/SignalRProducer.cs index fd690dfaf..e539e947e 100644 --- a/src/SignalR/src/Eventuous.SignalR.Server/SignalRProducer.cs +++ b/src/SignalR/src/Eventuous.SignalR.Server/SignalRProducer.cs @@ -12,8 +12,6 @@ namespace Eventuous.SignalR.Server; public class SignalRProducer(IHubContext hubContext) : BaseProducer(new() { MessagingSystem = "signalr" }) where THub : Hub { - [RequiresDynamicCode("Only works with AOT when using DefaultStaticEventSerializer")] - [RequiresUnreferencedCode("Only works with AOT when using DefaultStaticEventSerializer")] protected override async Task ProduceMessages( StreamName stream, IEnumerable messages, diff --git a/src/SignalR/src/Eventuous.SignalR.Server/SubscriptionGateway.cs b/src/SignalR/src/Eventuous.SignalR.Server/SubscriptionGateway.cs index e5ebc0b14..bc09546d0 100644 --- a/src/SignalR/src/Eventuous.SignalR.Server/SubscriptionGateway.cs +++ b/src/SignalR/src/Eventuous.SignalR.Server/SubscriptionGateway.cs @@ -22,7 +22,7 @@ public class SubscriptionGateway( : IAsyncDisposable where THub : Hub { readonly SubscriptionFactory _subscriptionFactory = options.SubscriptionFactory; - readonly IEventSerializer _eventSerializer = eventSerializer ?? DefaultEventSerializer.Instance; + readonly IEventSerializer _eventSerializer = eventSerializer ?? EventSerializer.Default; readonly ILogger _logger = loggerFactory.CreateLogger>(); readonly ConcurrentDictionary<(string ConnectionId, string Stream), SubscriptionState> _subscriptions = new(); diff --git a/src/SignalR/test/Eventuous.Tests.SignalR.Integration/Eventuous.Tests.SignalR.Integration.csproj b/src/SignalR/test/Eventuous.Tests.SignalR.Integration/Eventuous.Tests.SignalR.Integration.csproj index 6cd00723a..abf6590e2 100644 --- a/src/SignalR/test/Eventuous.Tests.SignalR.Integration/Eventuous.Tests.SignalR.Integration.csproj +++ b/src/SignalR/test/Eventuous.Tests.SignalR.Integration/Eventuous.Tests.SignalR.Integration.csproj @@ -8,6 +8,7 @@ + diff --git a/src/SignalR/test/Eventuous.Tests.SignalR.Integration/TestSetup.cs b/src/SignalR/test/Eventuous.Tests.SignalR.Integration/TestSetup.cs new file mode 100644 index 000000000..36a7e73f7 --- /dev/null +++ b/src/SignalR/test/Eventuous.Tests.SignalR.Integration/TestSetup.cs @@ -0,0 +1,12 @@ +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Text.Json; + +namespace Eventuous.Tests.SignalR.Integration; + +static class TestSetup { + [ModuleInitializer] + [SuppressMessage("Usage", "CA2255")] + internal static void Initialize() + => EventSerializer.SetDefault(new DefaultEventSerializer(new(JsonSerializerDefaults.Web))); +} diff --git a/src/SignalR/test/Eventuous.Tests.SignalR/Eventuous.Tests.SignalR.csproj b/src/SignalR/test/Eventuous.Tests.SignalR/Eventuous.Tests.SignalR.csproj index b67c99fc8..6af5e96dd 100644 --- a/src/SignalR/test/Eventuous.Tests.SignalR/Eventuous.Tests.SignalR.csproj +++ b/src/SignalR/test/Eventuous.Tests.SignalR/Eventuous.Tests.SignalR.csproj @@ -5,6 +5,7 @@ + diff --git a/src/SignalR/test/Eventuous.Tests.SignalR/SignalRTransformTests.cs b/src/SignalR/test/Eventuous.Tests.SignalR/SignalRTransformTests.cs index 1b05667d3..1773fa362 100644 --- a/src/SignalR/test/Eventuous.Tests.SignalR/SignalRTransformTests.cs +++ b/src/SignalR/test/Eventuous.Tests.SignalR/SignalRTransformTests.cs @@ -10,7 +10,7 @@ public class SignalRTransformTests { [Test] public async Task Transform_CreatesCorrectEnvelope() { TypeMap.RegisterKnownEventTypes(typeof(TransformTestEvent).Assembly); - var serializer = DefaultEventSerializer.Instance; + var serializer = EventSerializer.Default; var transform = SignalRTransform.Create("conn-1", "Test-1", serializer); var ctx = new MessageConsumeContext( @@ -44,7 +44,7 @@ public async Task Transform_CreatesCorrectEnvelope() { [Test] public async Task Transform_IncludesMetadataWhenPresent() { TypeMap.RegisterKnownEventTypes(typeof(TransformTestEvent).Assembly); - var serializer = DefaultEventSerializer.Instance; + var serializer = EventSerializer.Default; var transform = SignalRTransform.Create("conn-2", "Test-2", serializer); var meta = new Metadata { ["key1"] = "value1" }; diff --git a/src/SignalR/test/Eventuous.Tests.SignalR/TestSetup.cs b/src/SignalR/test/Eventuous.Tests.SignalR/TestSetup.cs new file mode 100644 index 000000000..2518ee1cf --- /dev/null +++ b/src/SignalR/test/Eventuous.Tests.SignalR/TestSetup.cs @@ -0,0 +1,12 @@ +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Text.Json; + +namespace Eventuous.Tests.SignalR; + +static class TestSetup { + [ModuleInitializer] + [SuppressMessage("Usage", "CA2255")] + internal static void Initialize() + => EventSerializer.SetDefault(new DefaultEventSerializer(new(JsonSerializerDefaults.Web))); +} diff --git a/src/Sqlite/src/Eventuous.Sqlite/SqliteStore.cs b/src/Sqlite/src/Eventuous.Sqlite/SqliteStore.cs index c93565ea0..010fe1da0 100644 --- a/src/Sqlite/src/Eventuous.Sqlite/SqliteStore.cs +++ b/src/Sqlite/src/Eventuous.Sqlite/SqliteStore.cs @@ -74,8 +74,6 @@ NewPersistedEvent[] events ) => throw new NotSupportedException("SQLite does not use GetAppendCommand. AppendEvents is overridden directly."); - [RequiresDynamicCode("Only works with AOT when using DefaultStaticEventSerializer")] - [RequiresUnreferencedCode("Only works with AOT when using DefaultStaticEventSerializer")] public override async Task AppendEvents( StreamName stream, ExpectedStreamVersion expectedVersion, @@ -107,8 +105,6 @@ CancellationToken cancellationToken } /// - [RequiresDynamicCode("Only works with AOT when using DefaultStaticEventSerializer")] - [RequiresUnreferencedCode("Only works with AOT when using DefaultStaticEventSerializer")] public override async Task AppendEvents(IReadOnlyCollection appends, CancellationToken cancellationToken) { if (appends.Count == 0) return []; @@ -230,8 +226,6 @@ RETURNING global_position return new((ulong)lastGlobalPosition, newVersion); } - [RequiresUnreferencedCode("Calls Eventuous.IEventSerializer.SerializeEvent(Object)")] - [RequiresDynamicCode("Calls Eventuous.IEventSerializer.SerializeEvent(Object)")] NewPersistedEvent Convert(NewStreamEvent evt) { var data = Serializer.SerializeEvent(evt.Payload!); var meta = MetaSerializer.Serialize(evt.Metadata); diff --git a/src/Sqlite/test/Eventuous.Tests.Sqlite/Eventuous.Tests.Sqlite.csproj b/src/Sqlite/test/Eventuous.Tests.Sqlite/Eventuous.Tests.Sqlite.csproj index 7b1670dd0..b8ca40d56 100644 --- a/src/Sqlite/test/Eventuous.Tests.Sqlite/Eventuous.Tests.Sqlite.csproj +++ b/src/Sqlite/test/Eventuous.Tests.Sqlite/Eventuous.Tests.Sqlite.csproj @@ -20,5 +20,6 @@ +