Skip to content

Commit cf881fd

Browse files
committed
Added AOT compatibility to assembly and dependency context DI extensions.
1 parent 4c5bc7a commit cf881fd

File tree

8 files changed

+63
-44
lines changed

8 files changed

+63
-44
lines changed

DependencyInjection/src/AppCoreNet.Extensions.DependencyInjection.AssemblyExtensions/AssemblyReflectionBuilderExtensions.cs

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Copyright (c) The AppCore .NET project.
33

44
using System;
5+
using System.Diagnostics.CodeAnalysis;
56
using AppCoreNet.Diagnostics;
67
using AppCoreNet.Extensions.DependencyInjection.Facilities;
78

@@ -10,6 +11,7 @@ namespace AppCoreNet.Extensions.DependencyInjection;
1011
/// <summary>
1112
/// Provides extension methods to resolve service descriptors and facilities by reflection.
1213
/// </summary>
14+
[RequiresUnreferencedCode("Uses reflection to discover services.")]
1315
public static class AssemblyReflectionBuilderExtensions
1416
{
1517
/// <summary>
@@ -33,12 +35,21 @@ public static IServiceDescriptorReflectionBuilder Assemblies(
3335
/// Adds service descriptors from the calling assembly by reflection.
3436
/// </summary>
3537
/// <param name="builder">The <see cref="IServiceDescriptorReflectionBuilder"/>.</param>
38+
/// <param name="configure">The delegate to configure the <see cref="AssemblyResolver"/>.</param>
3639
/// <returns>The <see cref="IServiceDescriptorReflectionBuilder"/> to allow chaining.</returns>
3740
/// <exception cref="ArgumentNullException">Argument <paramref name="builder"/> is <c>null</c>. </exception>
38-
public static IServiceDescriptorReflectionBuilder Assembly(this IServiceDescriptorReflectionBuilder builder)
41+
public static IServiceDescriptorReflectionBuilder Assembly(
42+
this IServiceDescriptorReflectionBuilder builder,
43+
Action<AssemblyServiceDescriptorResolver>? configure = null)
3944
{
4045
var assembly = System.Reflection.Assembly.GetCallingAssembly();
41-
return Assemblies(builder, c => c.Add(assembly));
46+
return Assemblies(
47+
builder,
48+
c =>
49+
{
50+
c.Add(assembly);
51+
configure?.Invoke(c);
52+
});
4253
}
4354

4455
/// <summary>
@@ -67,10 +78,14 @@ public static IFacilityReflectionBuilder Assemblies(
6778
/// <exception cref="ArgumentNullException">Argument <paramref name="builder"/> or <paramref name="configure"/> is <c>null</c>. </exception>
6879
public static IFacilityReflectionBuilder Assembly(
6980
this IFacilityReflectionBuilder builder,
70-
Action<AssemblyResolver> configure)
81+
Action<AssemblyResolver>? configure = null)
7182
{
7283
var assembly = System.Reflection.Assembly.GetCallingAssembly();
73-
return Assemblies(builder, c => c.Add(assembly));
84+
return Assemblies(builder, c =>
85+
{
86+
c.Add(assembly);
87+
configure?.Invoke(c);
88+
});
7489
}
7590

7691
/// <summary>
@@ -99,9 +114,13 @@ public static IFacilityExtensionReflectionBuilder Assemblies(
99114
/// <exception cref="ArgumentNullException">Argument <paramref name="builder"/> or <paramref name="configure"/> is <c>null</c>. </exception>
100115
public static IFacilityExtensionReflectionBuilder Assembly(
101116
this IFacilityExtensionReflectionBuilder builder,
102-
Action<AssemblyResolver> configure)
117+
Action<AssemblyResolver>? configure = null)
103118
{
104119
var assembly = System.Reflection.Assembly.GetCallingAssembly();
105-
return Assemblies(builder, c => c.Add(assembly));
120+
return Assemblies(builder, c =>
121+
{
122+
c.Add(assembly);
123+
configure?.Invoke(c);
124+
});
106125
}
107126
}

DependencyInjection/src/AppCoreNet.Extensions.DependencyInjection.AssemblyExtensions/AssemblyScanner.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System;
55
using System.Collections.Generic;
6+
using System.Diagnostics.CodeAnalysis;
67
using System.Linq;
78
using System.Reflection;
89
using AppCoreNet.Diagnostics;
@@ -12,6 +13,7 @@ namespace AppCoreNet.Extensions.DependencyInjection;
1213
/// <summary>
1314
/// Represents a type used to scan assemblies for exported types.
1415
/// </summary>
16+
[RequiresUnreferencedCode("Uses reflection to discover types.")]
1517
public class AssemblyScanner
1618
{
1719
private static readonly List<string> _defaultExcludedAssemblies =

DependencyInjection/src/AppCoreNet.Extensions.DependencyInjection.AssemblyExtensions/AssemblyServiceDescriptorResolver.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System;
55
using System.Collections.Generic;
6+
using System.Diagnostics.CodeAnalysis;
67
using System.Reflection;
78
using AppCoreNet.Diagnostics;
89
using Microsoft.Extensions.DependencyInjection;
@@ -12,6 +13,7 @@ namespace AppCoreNet.Extensions.DependencyInjection;
1213
/// <summary>
1314
/// Builds an <see cref="IEnumerable{T}"/> of <see cref="ServiceDescriptor"/> by scanning assemblies.
1415
/// </summary>
16+
[RequiresUnreferencedCode("Uses reflection to discover services.")]
1517
public class AssemblyServiceDescriptorResolver : IServiceDescriptorResolver
1618
{
1719
private readonly List<Assembly> _assemblies = new();

DependencyInjection/src/AppCoreNet.Extensions.DependencyInjection.AssemblyExtensions/Facilities/AssemblyResolver.cs

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System;
55
using System.Collections.Generic;
6+
using System.Diagnostics.CodeAnalysis;
67
using System.Linq;
78
using System.Reflection;
89
using AppCoreNet.Diagnostics;
@@ -13,6 +14,7 @@ namespace AppCoreNet.Extensions.DependencyInjection.Facilities;
1314
/// <summary>
1415
/// Builds an <see cref="IEnumerable{T}"/> of <see cref="IFacility"/> by scanning assemblies.
1516
/// </summary>
17+
[RequiresUnreferencedCode("Uses reflection to discover types.")]
1618
public class AssemblyResolver : IFacilityResolver, IFacilityExtensionResolver
1719
{
1820
private readonly IActivator _activator;
@@ -120,24 +122,12 @@ IEnumerable<IFacility> IFacilityResolver.Resolve()
120122
.Select(facilityType => (IFacility)_activator.CreateInstance(facilityType)!);
121123
}
122124

123-
private IFacilityExtension<IFacility> CreateExtension(Type extensionType)
124-
{
125-
Type contractType = extensionType.GetInterfaces()
126-
.First(i => i.GetGenericTypeDefinition() == typeof(IFacilityExtension<>))
127-
.GenericTypeArguments[0];
128-
129-
Type extensionWrapperType = typeof(FacilityExtensionWrapper<>).MakeGenericType(contractType);
130-
object extension = _activator.CreateInstance(extensionType)!;
131-
132-
return (IFacilityExtension<IFacility>)System.Activator.CreateInstance(extensionWrapperType, extension)!;
133-
}
134-
135125
/// <inheritdoc />
136-
IEnumerable<IFacilityExtension<IFacility>> IFacilityExtensionResolver.Resolve(Type facilityType)
126+
IEnumerable<IFacilityExtension> IFacilityExtensionResolver.Resolve(Type facilityType)
137127
{
138128
Ensure.Arg.NotNull(facilityType);
139129

140-
var scanner = new AssemblyScanner(typeof(IFacilityExtension<>).MakeGenericType(facilityType), _assemblies)
130+
var scanner = new AssemblyScanner(typeof(IFacilityExtension<>), _assemblies)
141131
{
142132
IncludePrivateTypes = _withPrivateTypes,
143133
};
@@ -149,6 +139,18 @@ IEnumerable<IFacilityExtension<IFacility>> IFacilityExtensionResolver.Resolve(Ty
149139
scanner.Filters.Add(filter);
150140

151141
return scanner.ScanAssemblies()
152-
.Select(CreateExtension);
142+
.Where(t => IsCompatibleExtensionType(t, facilityType))
143+
.Select(t => (IFacilityExtension)_activator.CreateInstance(t)!);
144+
145+
static bool IsCompatibleExtensionType(Type extensionType, Type facilityType)
146+
{
147+
IEnumerable<Type> extensionInterfaces =
148+
extensionType.GetInterfaces()
149+
.Where(t => t.IsGenericType
150+
&& t.GetGenericTypeDefinition() == typeof(IFacilityExtension<>));
151+
152+
IEnumerable<Type> extendedFacilityTypes = extensionInterfaces.Select(t => t.GenericTypeArguments[0]);
153+
return extendedFacilityTypes.Any(t => t.IsAssignableFrom(facilityType));
154+
}
153155
}
154156
}

DependencyInjection/src/AppCoreNet.Extensions.DependencyInjection.AssemblyExtensions/Facilities/FacilityExtensionWrapper.cs

Lines changed: 0 additions & 22 deletions
This file was deleted.

DependencyInjection/src/AppCoreNet.Extensions.DependencyInjection.DependencyModelExtensions/DependencyContextReflectionBuilderExtensions.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Copyright (c) The AppCore .NET project.
33

44
using System;
5+
using System.Diagnostics.CodeAnalysis;
56
using AppCoreNet.Diagnostics;
67
using AppCoreNet.Extensions.DependencyInjection.Facilities;
78
using DependencyModel = Microsoft.Extensions.DependencyModel;
@@ -11,8 +12,13 @@ namespace AppCoreNet.Extensions.DependencyInjection;
1112
/// <summary>
1213
/// Provides extension methods to resolve service descriptors and facilities by reflection.
1314
/// </summary>
15+
[RequiresUnreferencedCode("Uses reflection to discover services.")]
1416
public static class DependencyContextReflectionBuilderExtensions
1517
{
18+
private const string RequiresAssemblyFilesMessage =
19+
"DependencyContext for an assembly from a application published as single-file is not supported.";
20+
21+
[RequiresAssemblyFiles(RequiresAssemblyFilesMessage)]
1622
private static DependencyModel.DependencyContext ResolveDependencyContext(DependencyModel.DependencyContext? context)
1723
{
1824
context ??= DependencyModel.DependencyContext.Default;
@@ -33,6 +39,7 @@ private static DependencyModel.DependencyContext ResolveDependencyContext(Depend
3339
/// <param name="configure">The delegate to configure the <see cref="DependencyContextServiceDescriptorResolver"/>.</param>
3440
/// <returns>The <see cref="IServiceDescriptorReflectionBuilder"/> to allow chaining.</returns>
3541
/// <exception cref="ArgumentNullException">Argument <paramref name="builder"/> is <c>null</c>. </exception>
42+
[RequiresAssemblyFiles(RequiresAssemblyFilesMessage)]
3643
public static IServiceDescriptorReflectionBuilder DependencyContext(
3744
this IServiceDescriptorReflectionBuilder builder,
3845
Action<DependencyContextServiceDescriptorResolver> configure)
@@ -51,6 +58,7 @@ public static IServiceDescriptorReflectionBuilder DependencyContext(
5158
/// <param name="configure">The delegate to configure the <see cref="DependencyContextServiceDescriptorResolver"/>.</param>
5259
/// <returns>The <see cref="IServiceDescriptorReflectionBuilder"/> to allow chaining.</returns>
5360
/// <exception cref="ArgumentNullException">Argument <paramref name="builder"/> is <c>null</c>. </exception>
61+
[RequiresAssemblyFiles(RequiresAssemblyFilesMessage)]
5462
public static IServiceDescriptorReflectionBuilder DependencyContext(
5563
this IServiceDescriptorReflectionBuilder builder,
5664
DependencyModel.DependencyContext? context = null,
@@ -74,6 +82,7 @@ public static IServiceDescriptorReflectionBuilder DependencyContext(
7482
/// <param name="configure">The delegate to configure the <see cref="DependencyContextResolver"/>.</param>
7583
/// <returns>The <see cref="IServiceDescriptorReflectionBuilder"/> to allow chaining.</returns>
7684
/// <exception cref="ArgumentNullException">Argument <paramref name="builder"/> or <paramref name="configure"/> is <c>null</c>. </exception>
85+
[RequiresAssemblyFiles(RequiresAssemblyFilesMessage)]
7786
public static IFacilityReflectionBuilder DependencyContext(
7887
this IFacilityReflectionBuilder builder,
7988
Action<DependencyContextResolver> configure)
@@ -92,6 +101,7 @@ public static IFacilityReflectionBuilder DependencyContext(
92101
/// <param name="configure">The delegate to configure the <see cref="DependencyContextResolver"/>.</param>
93102
/// <returns>The <see cref="IServiceDescriptorReflectionBuilder"/> to allow chaining.</returns>
94103
/// <exception cref="ArgumentNullException">Argument <paramref name="builder"/> or <paramref name="configure"/> is <c>null</c>. </exception>
104+
[RequiresAssemblyFiles(RequiresAssemblyFilesMessage)]
95105
public static IFacilityReflectionBuilder DependencyContext(
96106
this IFacilityReflectionBuilder builder,
97107
DependencyModel.DependencyContext? context = null,
@@ -115,6 +125,7 @@ public static IFacilityReflectionBuilder DependencyContext(
115125
/// <param name="configure">The delegate to configure the <see cref="DependencyContextResolver"/>.</param>
116126
/// <returns>The <see cref="IFacilityExtensionReflectionBuilder"/> to allow chaining.</returns>
117127
/// <exception cref="ArgumentNullException">Argument <paramref name="builder"/> or <paramref name="configure"/> is <c>null</c>. </exception>
128+
[RequiresAssemblyFiles(RequiresAssemblyFilesMessage)]
118129
public static IFacilityExtensionReflectionBuilder DependencyContext(
119130
this IFacilityExtensionReflectionBuilder builder,
120131
Action<DependencyContextResolver> configure)
@@ -134,6 +145,7 @@ public static IFacilityExtensionReflectionBuilder DependencyContext(
134145
/// <returns>The <see cref="IFacilityExtensionReflectionBuilder"/> to allow chaining.</returns>
135146
/// <exception cref="ArgumentNullException">Argument <paramref name="builder"/> or <paramref name="configure"/> is <c>null</c>.</exception>
136147
/// <exception cref="NotSupportedException">Argument <paramref name="context"/> is <c>null</c> and no default DependencyContext was available.</exception>
148+
[RequiresAssemblyFiles(RequiresAssemblyFilesMessage)]
137149
public static IFacilityExtensionReflectionBuilder DependencyContext(
138150
this IFacilityExtensionReflectionBuilder builder,
139151
DependencyModel.DependencyContext? context = null,

DependencyInjection/src/AppCoreNet.Extensions.DependencyInjection.DependencyModelExtensions/DependencyContextServiceDescriptorResolver.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System;
55
using System.Collections.Generic;
6+
using System.Diagnostics.CodeAnalysis;
67
using System.Linq;
78
using System.Reflection;
89
using AppCoreNet.Diagnostics;
@@ -15,6 +16,7 @@ namespace AppCoreNet.Extensions.DependencyInjection;
1516
/// Builds an <see cref="IEnumerable{T}"/> of <see cref="ServiceDescriptor"/> by scanning assemblies in a
1617
/// <see cref="DependencyContext"/>.
1718
/// </summary>
19+
[RequiresUnreferencedCode("Uses reflection to discover services.")]
1820
public class DependencyContextServiceDescriptorResolver : IServiceDescriptorResolver
1921
{
2022
private readonly AssemblyServiceDescriptorResolver _source;

DependencyInjection/src/AppCoreNet.Extensions.DependencyInjection.DependencyModelExtensions/Facilities/DependencyContextResolver.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System;
55
using System.Collections.Generic;
6+
using System.Diagnostics.CodeAnalysis;
67
using System.Linq;
78
using System.Reflection;
89
using AppCoreNet.Diagnostics;
@@ -16,6 +17,7 @@ namespace AppCoreNet.Extensions.DependencyInjection.Facilities;
1617
/// Builds an <see cref="IEnumerable{T}"/> of <see cref="IFacility"/> by scanning assemblies in a
1718
/// <see cref="DependencyContext"/>.
1819
/// </summary>
20+
[RequiresUnreferencedCode("Uses reflection to discover services.")]
1921
public class DependencyContextResolver : IFacilityResolver, IFacilityExtensionResolver
2022
{
2123
private readonly AssemblyResolver _resolver;
@@ -97,7 +99,7 @@ IEnumerable<IFacility> IFacilityResolver.Resolve()
9799
}
98100

99101
/// <inheritdoc />
100-
IEnumerable<IFacilityExtension<IFacility>> IFacilityExtensionResolver.Resolve(Type facilityType)
102+
IEnumerable<IFacilityExtension> IFacilityExtensionResolver.Resolve(Type facilityType)
101103
{
102104
return ((IFacilityExtensionResolver)_resolver).Resolve(facilityType);
103105
}

0 commit comments

Comments
 (0)