Skip to content

Commit b2ac472

Browse files
authored
Merge pull request #3 from snowberry-software/develop
develop
2 parents 3823d86 + 49d729b commit b2ac472

24 files changed

+731
-155
lines changed

src/NuGetPackage.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<Platforms>AnyCPU;x64;x86</Platforms>
55

66
<Authors>Snowberry Software</Authors>
7-
<AssemblyVersion>1.0.2.0</AssemblyVersion>
7+
<AssemblyVersion>1.0.3.0</AssemblyVersion>
88
<VersionPrefix>$(AssemblyVersion)</VersionPrefix>
99
<VersionSuffix>alpha</VersionSuffix>
1010

src/PolySharp.props

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<Project>
2+
3+
<PropertyGroup>
4+
<PolySharpExcludeGeneratedTypes>*</PolySharpExcludeGeneratedTypes>
5+
<PolySharpIncludeRuntimeSupportedAttributes>true</PolySharpIncludeRuntimeSupportedAttributes>
6+
7+
<PolySharpIncludeGeneratedTypes>
8+
System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute;
9+
System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes;
10+
System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute;
11+
System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute;
12+
System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute;
13+
System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute;
14+
</PolySharpIncludeGeneratedTypes>
15+
</PropertyGroup>
16+
17+
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
18+
<PackageReference Include="PolySharp" Version="1.15.0">
19+
<PrivateAssets>all</PrivateAssets>
20+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
21+
</PackageReference>
22+
</ItemGroup>
23+
24+
</Project>

src/Snowberry.Mediator.Abstractions/Snowberry.Mediator.Abstractions.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@
55
<ImplicitUsings>enable</ImplicitUsings>
66
<Nullable>enable</Nullable>
77
<LangVersion>latest</LangVersion>
8+
<IsAotCompatible Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net7.0'))">true</IsAotCompatible>
89

910
<!-- Package -->
1011
<Description>The abstractions required for the main package.</Description>
1112
</PropertyGroup>
1213

1314
<ItemGroup Condition="$(TargetFramework) == 'netstandard2.0'">
1415
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.6.3" />
15-
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.9" />
16+
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.10" />
1617
</ItemGroup>
1718

1819
<Import Project="../NuGetPackage.props" />

src/Snowberry.Mediator.DependencyInjection.Shared/Contracts/IServiceContext.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
namespace Snowberry.Mediator.DependencyInjection.Shared.Contracts;
1+
using System.Diagnostics.CodeAnalysis;
2+
3+
namespace Snowberry.Mediator.DependencyInjection.Shared.Contracts;
24

35
/// <summary>
46
/// Defines a context for registering services with specific lifetimes.
@@ -26,7 +28,7 @@ public interface IServiceContext
2628
/// <param name="serviceType">The service type.</param>
2729
/// <param name="implementationType">The implementation type.</param>
2830
/// <param name="lifetime">The service lifetime.</param>
29-
void TryRegister(Type serviceType, Type implementationType, RegistrationServiceLifetime lifetime);
31+
void TryRegister(Type serviceType, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type implementationType, RegistrationServiceLifetime lifetime);
3032

3133
/// <summary>
3234
/// Registers a singleton instance of a service.

src/Snowberry.Mediator.DependencyInjection.Shared/DependencyInjectionHelper.cs

Lines changed: 100 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
using Snowberry.Mediator.Abstractions;
1+
using System.Diagnostics.CodeAnalysis;
2+
using System.Reflection;
3+
using Snowberry.Mediator.Abstractions;
24
using Snowberry.Mediator.Abstractions.Handler;
35
using Snowberry.Mediator.Abstractions.Pipeline;
46
using Snowberry.Mediator.DependencyInjection.Shared.Contracts;
@@ -14,106 +16,143 @@ namespace Snowberry.Mediator.DependencyInjection.Shared;
1416
/// </summary>
1517
public static class DependencyInjectionHelper
1618
{
19+
public delegate void CustomAddCallbackDelegate(
20+
IServiceContext serviceContext,
21+
MediatorOptions options,
22+
RegistrationServiceLifetime serviceLifetime,
23+
HandlerCollection handlerCollection,
24+
bool append);
25+
1726
/// <summary>
1827
/// Adds Mediator services to the specified service context.
1928
/// </summary>
29+
/// <remarks>This variant ignores the <see cref="MediatorOptions.Assemblies"/> option to be more compatible with AOT scenarios.</remarks>
2030
/// <param name="serviceContext">The service context.</param>
2131
/// <param name="options">The options.</param>
2232
/// <param name="serviceLifetime">The service lifetime.</param>
2333
/// <param name="append">Whether to append to existing registrations or replace them.</param>
24-
public static void AddSnowberryMediator(
34+
/// <param name="customCallback">A custom callback to execute at the start during registration.</param>
35+
[RequiresDynamicCode("Creating generic handler types at runtime requires dynamic code. Use explicit handler registration for AOT compatibility.")]
36+
public static void AddSnowberryMediatorNoScan(
2537
IServiceContext serviceContext,
2638
MediatorOptions options,
2739
RegistrationServiceLifetime serviceLifetime,
28-
bool append)
40+
bool append,
41+
CustomAddCallbackDelegate? customCallback)
2942
{
3043
if (!append || !serviceContext.IsServiceRegistered<IMediator>())
3144
serviceContext.TryRegister(typeof(IMediator), typeof(Mediator), serviceLifetime);
3245

33-
var allHandlers = new List<RequestHandlerInfo>();
34-
var allStreamHandlers = new List<StreamRequestHandlerInfo>();
35-
var allPipelineBehaviorHandlers = new List<PipelineBehaviorHandlerInfo>();
36-
var allStreamPipelineBehaviorHandlers = new List<StreamPipelineBehaviorHandlerInfo>();
37-
var allNotificationHandlers = new List<NotificationHandlerInfo>();
38-
39-
if (options.Assemblies != null && options.Assemblies.Count > 0)
40-
{
41-
for (int i = 0; i < options.Assemblies.Count; i++)
42-
{
43-
var assembly = options.Assemblies[i];
44-
45-
var scanResult = MediatorAssemblyHelper.ScanAssembly(assembly);
46-
47-
if (scanResult.RequestHandlerTypes != null)
48-
for (int j = 0; j < scanResult.RequestHandlerTypes.Count; j++)
49-
allHandlers.Add(scanResult.RequestHandlerTypes[j]);
50-
51-
if (scanResult.StreamRequestHandlerTypes != null)
52-
for (int j = 0; j < scanResult.StreamRequestHandlerTypes.Count; j++)
53-
allStreamHandlers.Add(scanResult.StreamRequestHandlerTypes[j]);
46+
var handlerCollection = new HandlerCollection();
5447

55-
if (options.RegisterPipelineBehaviors && options.ScanPipelineBehaviors && scanResult.PipelineBehaviorTypes != null)
56-
for (int j = 0; j < scanResult.PipelineBehaviorTypes.Count; j++)
57-
allPipelineBehaviorHandlers.Add(scanResult.PipelineBehaviorTypes[j]);
58-
59-
if (options.RegisterStreamPipelineBehaviors && options.ScanStreamPipelineBehaviors && scanResult.StreamPipelineBehaviorTypes != null)
60-
for (int j = 0; j < scanResult.StreamPipelineBehaviorTypes.Count; j++)
61-
allStreamPipelineBehaviorHandlers.Add(scanResult.StreamPipelineBehaviorTypes[j]);
62-
63-
if (options.RegisterNotificationHandlers && options.ScanNotificationHandlers && scanResult.NotificationHandlerTypes != null)
64-
for (int j = 0; j < scanResult.NotificationHandlerTypes.Count; j++)
65-
allNotificationHandlers.Add(scanResult.NotificationHandlerTypes[j]);
66-
}
67-
}
48+
customCallback?.Invoke(serviceContext, options, serviceLifetime, handlerCollection, append);
6849

6950
var pipelineBehaviorType = typeof(IPipelineBehavior<,>);
7051
var streamPipelineBehaviorType = typeof(IStreamPipelineBehavior<,>);
7152
var requestHandlerType = typeof(IRequestHandler<,>);
7253
var streamRequestHandlerType = typeof(IStreamRequestHandler<,>);
7354

7455
if (options.PipelineBehaviorTypes != null && options.RegisterPipelineBehaviors)
75-
MediatorAssemblyHelper.ParseHandlerInfo(pipelineBehaviorType, options.PipelineBehaviorTypes, allPipelineBehaviorHandlers);
56+
MediatorAssemblyHelper.ParseHandlerInfo(pipelineBehaviorType, options.PipelineBehaviorTypes, handlerCollection.AllPipelineBehaviorHandlers);
7657

7758
if (options.RequestHandlerTypes != null && options.RegisterRequestHandlers)
78-
MediatorAssemblyHelper.ParseHandlerInfo(requestHandlerType, options.RequestHandlerTypes, allHandlers);
59+
MediatorAssemblyHelper.ParseHandlerInfo(requestHandlerType, options.RequestHandlerTypes, handlerCollection.AllHandlers);
7960

8061
if (options.StreamRequestHandlerTypes != null && options.RegisterStreamRequestHandlers)
81-
MediatorAssemblyHelper.ParseHandlerInfo(streamRequestHandlerType, options.StreamRequestHandlerTypes, allStreamHandlers);
62+
MediatorAssemblyHelper.ParseHandlerInfo(streamRequestHandlerType, options.StreamRequestHandlerTypes, handlerCollection.AllStreamHandlers);
8263

8364
if (options.StreamPipelineBehaviorTypes != null && options.RegisterStreamPipelineBehaviors)
84-
MediatorAssemblyHelper.ParseHandlerInfo(streamPipelineBehaviorType, options.StreamPipelineBehaviorTypes, allStreamPipelineBehaviorHandlers);
65+
MediatorAssemblyHelper.ParseHandlerInfo(streamPipelineBehaviorType, options.StreamPipelineBehaviorTypes, handlerCollection.AllStreamPipelineBehaviorHandlers);
8566

8667
if (options.NotificationHandlerTypes != null && options.RegisterNotificationHandlers)
87-
MediatorAssemblyHelper.ParseNotificationHandlers(options.NotificationHandlerTypes, allNotificationHandlers);
68+
MediatorAssemblyHelper.ParseNotificationHandlers(options.NotificationHandlerTypes, handlerCollection.AllNotificationHandlers);
8869

89-
for (int i = 0; i < allHandlers.Count; i++)
70+
for (int i = 0; i < handlerCollection.AllHandlers.Count; i++)
9071
{
91-
var handlerInfo = allHandlers[i];
72+
var handlerInfo = handlerCollection.AllHandlers[i];
9273
serviceContext.TryRegister(handlerInfo.CreateRequestHandlerInterfaceType(), handlerInfo.HandlerType, serviceLifetime);
9374
}
9475

95-
for (int i = 0; i < allStreamHandlers.Count; i++)
76+
for (int i = 0; i < handlerCollection.AllStreamHandlers.Count; i++)
9677
{
97-
var handlerInfo = allStreamHandlers[i];
78+
var handlerInfo = handlerCollection.AllStreamHandlers[i];
9879
serviceContext.TryRegister(handlerInfo.CreateStreamRequestHandlerInterfaceType(), handlerInfo.HandlerType, serviceLifetime);
9980
}
10081

101-
if (options.RegisterPipelineBehaviors && allPipelineBehaviorHandlers.Count > 0)
82+
if (options.RegisterPipelineBehaviors && handlerCollection.AllPipelineBehaviorHandlers.Count > 0)
10283
AddPipelineBehaviors<IGlobalPipelineRegistry, GlobalPipelineRegistry, PipelineBehaviorHandlerInfo>(
10384
serviceContext,
10485
serviceLifetime,
105-
allPipelineBehaviorHandlers,
86+
handlerCollection.AllPipelineBehaviorHandlers,
10687
append);
10788

108-
if (options.RegisterStreamPipelineBehaviors && allStreamPipelineBehaviorHandlers.Count > 0)
89+
if (options.RegisterStreamPipelineBehaviors && handlerCollection.AllStreamPipelineBehaviorHandlers.Count > 0)
10990
AddPipelineBehaviors<IGlobalStreamPipelineRegistry, GlobalStreamPipelineRegistry, StreamPipelineBehaviorHandlerInfo>(
11091
serviceContext,
11192
serviceLifetime,
112-
allStreamPipelineBehaviorHandlers,
93+
handlerCollection.AllStreamPipelineBehaviorHandlers,
11394
append);
11495

115-
if (options.RegisterNotificationHandlers && allNotificationHandlers.Count > 0)
116-
AddNotificationHandlers(serviceContext, serviceLifetime, allNotificationHandlers, append);
96+
if (options.RegisterNotificationHandlers && handlerCollection.AllNotificationHandlers.Count > 0)
97+
AddNotificationHandlers(serviceContext, serviceLifetime, handlerCollection.AllNotificationHandlers, append);
98+
}
99+
100+
/// <summary>
101+
/// Adds Mediator services to the specified service context.
102+
/// </summary>
103+
/// <param name="serviceContext">The service context.</param>
104+
/// <param name="options">The options.</param>
105+
/// <param name="serviceLifetime">The service lifetime.</param>
106+
/// <param name="append">Whether to append to existing registrations or replace them.</param>
107+
/// <param name="customCallback">A custom callback to execute at the start during registration.</param>
108+
[RequiresUnreferencedCode("Assembly scanning requires unreferenced code. Use explicit handler registration for AOT compatibility.")]
109+
[RequiresDynamicCode("Creating generic handler types at runtime requires dynamic code. Use explicit handler registration for AOT compatibility.")]
110+
public static void AddSnowberryMediator(
111+
IServiceContext serviceContext,
112+
MediatorOptions options,
113+
RegistrationServiceLifetime serviceLifetime,
114+
bool append,
115+
CustomAddCallbackDelegate? customCallback = null)
116+
{
117+
AddSnowberryMediatorNoScan(serviceContext, options, serviceLifetime, append, (_, _, _, handlerCollection, _) =>
118+
{
119+
if (options.Assemblies != null && options.Assemblies.Count > 0)
120+
{
121+
for (int i = 0; i < options.Assemblies.Count; i++)
122+
{
123+
var assembly = options.Assemblies[i];
124+
ScanAssembly(options, handlerCollection, assembly);
125+
}
126+
}
127+
128+
customCallback?.Invoke(serviceContext, options, serviceLifetime, handlerCollection, append);
129+
});
130+
}
131+
132+
[RequiresUnreferencedCode("Assembly scanning requires unreferenced code. Use explicit handler registration for AOT compatibility.")]
133+
public static void ScanAssembly(MediatorOptions options, HandlerCollection handlerCollection, Assembly assembly)
134+
{
135+
var scanResult = MediatorAssemblyHelper.ScanAssembly(assembly);
136+
137+
if (scanResult.RequestHandlerTypes != null)
138+
for (int j = 0; j < scanResult.RequestHandlerTypes.Count; j++)
139+
handlerCollection.AllHandlers.Add(scanResult.RequestHandlerTypes[j]);
140+
141+
if (scanResult.StreamRequestHandlerTypes != null)
142+
for (int j = 0; j < scanResult.StreamRequestHandlerTypes.Count; j++)
143+
handlerCollection.AllStreamHandlers.Add(scanResult.StreamRequestHandlerTypes[j]);
144+
145+
if (options.RegisterPipelineBehaviors && options.ScanPipelineBehaviors && scanResult.PipelineBehaviorTypes != null)
146+
for (int j = 0; j < scanResult.PipelineBehaviorTypes.Count; j++)
147+
handlerCollection.AllPipelineBehaviorHandlers.Add(scanResult.PipelineBehaviorTypes[j]);
148+
149+
if (options.RegisterStreamPipelineBehaviors && options.ScanStreamPipelineBehaviors && scanResult.StreamPipelineBehaviorTypes != null)
150+
for (int j = 0; j < scanResult.StreamPipelineBehaviorTypes.Count; j++)
151+
handlerCollection.AllStreamPipelineBehaviorHandlers.Add(scanResult.StreamPipelineBehaviorTypes[j]);
152+
153+
if (options.RegisterNotificationHandlers && options.ScanNotificationHandlers && scanResult.NotificationHandlerTypes != null)
154+
for (int j = 0; j < scanResult.NotificationHandlerTypes.Count; j++)
155+
handlerCollection.AllNotificationHandlers.Add(scanResult.NotificationHandlerTypes[j]);
117156
}
118157

119158
private static void AddPipelineBehaviors<TGlobalPipelineInterface, TGlobalPipelineRegistry, THandlerInfo>(
@@ -191,4 +230,13 @@ bool append
191230
serviceContext.TryRegister(handler.HandlerType, handler.HandlerType, serviceLifetime);
192231
}
193232
}
233+
234+
public class HandlerCollection
235+
{
236+
public readonly List<RequestHandlerInfo> AllHandlers = [];
237+
public readonly List<StreamRequestHandlerInfo> AllStreamHandlers = [];
238+
public readonly List<PipelineBehaviorHandlerInfo> AllPipelineBehaviorHandlers = [];
239+
public readonly List<StreamPipelineBehaviorHandlerInfo> AllStreamPipelineBehaviorHandlers = [];
240+
public readonly List<NotificationHandlerInfo> AllNotificationHandlers = [];
241+
}
194242
}

src/Snowberry.Mediator.DependencyInjection.Shared/Snowberry.Mediator.DependencyInjection.Shared.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
<TargetFramework>net9.0</TargetFramework>
55
<ImplicitUsings>enable</ImplicitUsings>
66
<Nullable>enable</Nullable>
7+
<IsAotCompatible>true</IsAotCompatible>
78

89
<!-- Package -->
910
<Description>A small helper library for supporting multiple Dependency Injection frameworks.</Description>

0 commit comments

Comments
 (0)