-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Problem
TimeWarp.Mediator currently uses reflection for discovering and invoking handlers, which makes it incompatible with .NET trimming and AOT (Ahead-of-Time compilation). This results in IL2104 trim warnings when used in projects that enable trimming.
Current Impact
When building applications with trimming enabled (e.g., standalone executables), we get:
error IL2104: Assembly 'TimeWarp.Mediator' produced trim warnings. For more information see https://aka.ms/il2104
This prevents downstream projects from creating trimmed/AOT executables. For example, in TimeWarp.Amuru, we had to disable trimming for standalone CLI tools because of these warnings.
Proposed Solution
Replace the reflection-based handler discovery and invocation with source generators. Source generators can:
- Discover handlers at compile-time
- Generate strongly-typed code for handler invocation
- Eliminate runtime reflection entirely
- Enable full AOT/trimming support
Benefits
- ✅ Full AOT compilation support
- ✅ Trimming compatibility (smaller executables)
- ✅ Better performance (no reflection overhead)
- ✅ Compile-time validation of handlers
- ✅ Better IntelliSense and debugging experience
Implementation Approach
-
Create a source generator that:
- Scans for classes implementing IRequestHandler/INotificationHandler
- Generates a registry/factory class with all handlers
- Generates invocation code without reflection
-
Update Mediator to use the generated code instead of reflection
-
Mark the library as trim-compatible and AOT-compatible
Example
Instead of:
// Runtime reflection to find handler
var handlerType = typeof(IRequestHandler<,>).MakeGenericType(requestType, responseType);
var handler = serviceProvider.GetService(handlerType);
var method = handlerType.GetMethod("Handle");
return await (Task)method.Invoke(handler, new[] { request, cancellationToken });
Generate:
// Generated at compile-time
return request switch
{
GetUserQuery query => await GetService<IRequestHandler<GetUserQuery, User>>().Handle(query, cancellationToken),
CreateUserCommand cmd => await GetService<IRequestHandler<CreateUserCommand, Result>>().Handle(cmd, cancellationToken),
// ... other handlers
_ => throw new HandlerNotFoundException(request.GetType())
};
References
- .NET Source Generators
- Making Libraries Trim-Compatible
- Native AOT Deployment
- Related issue in TimeWarp.Nuru: Add AOT/trimming support by eliminating reflection usage timewarp-nuru#43
- Related PR in TimeWarp.Amuru: feat: implement CLI utilities and improve CI/CD pipeline timewarp-amuru#19
Breaking Changes
This could potentially be implemented without breaking changes by:
- Keeping the same public API
- Using source generators internally
- Providing a compatibility layer for dynamic registration if needed
Priority
High - This blocks AOT adoption across all dependent projects and prevents creation of small, trimmed executables.