Skip to content

Commit 3cd3977

Browse files
authored
Dependency Injection Refinements (ChilliCream#6155)
1 parent 0c0ddf7 commit 3cd3977

17 files changed

Lines changed: 895 additions & 777 deletions

src/HotChocolate/Core/src/Execution/RequestExecutorResolver.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -320,14 +320,13 @@ await OnConfigureRequestExecutorOptionsAsync(context, setup, cancellationToken)
320320
OnConfigureSchemaServices(context, serviceCollection, setup);
321321

322322
var schemaServices = serviceCollection.BuildServiceProvider();
323-
// var combinedServices = schemaServices.Include(_applicationServices);
324323

325324
lazy.Schema =
326325
await CreateSchemaAsync(
327326
context,
328327
setup,
329328
executorOptions,
330-
schemaServices,
329+
schemaServices.Include(_applicationServices),
331330
typeModuleChangeMonitor,
332331
cancellationToken)
333332
.ConfigureAwait(false);

src/HotChocolate/Stitching/src/Stitching/Requests/BufferedRequest.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
using HotChocolate.Language;
33
using HotChocolate.Stitching.Properties;
44
using HotChocolate.Types;
5-
using HotChocolate.Types.Pagination;
65
using HotChocolate.Utilities;
76
using Microsoft.Extensions.DependencyInjection;
87
using static HotChocolate.Stitching.ThrowHelper;

src/HotChocolate/Utilities/src/Utilities/ActivatorHelper.cs

Lines changed: 61 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
using System;
22
using System.Collections.Concurrent;
33
using System.Collections.Generic;
4+
#if NET6_0_OR_GREATER
5+
using System.Diagnostics.CodeAnalysis;
6+
#endif
47
using System.Globalization;
58
using System.Linq;
69
using System.Linq.Expressions;
710
using System.Reflection;
811
using HotChocolate.Utilities.Properties;
12+
#if NET6_0_OR_GREATER
13+
using static System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes;
14+
#endif
915

1016
namespace HotChocolate.Utilities;
1117

@@ -20,10 +26,24 @@ internal static class ActivatorHelper
2026

2127
private static readonly ConcurrentDictionary<Type, CreateServiceDelegate> _cache = new();
2228

23-
public static CreateServiceDelegate<TService> CompileFactory<TService>() =>
24-
CompileFactory<TService>(typeof(TService));
29+
#if NET6_0_OR_GREATER
30+
public static CreateServiceDelegate<TService> CompileFactory<
31+
[DynamicallyAccessedMembers(PublicConstructors)] TService>()
32+
=> CompileFactory<TService>(typeof(TService));
33+
#else
34+
public static CreateServiceDelegate<TService> CompileFactory<TService>()
35+
=> CompileFactory<TService>(typeof(TService));
36+
#endif
2537

26-
public static CreateServiceDelegate<TService> CompileFactory<TService>(Type implementation)
38+
39+
#if NET6_0_OR_GREATER
40+
public static CreateServiceDelegate<TService> CompileFactory<TService>(
41+
[DynamicallyAccessedMembers(PublicConstructors)]
42+
Type implementation)
43+
#else
44+
public static CreateServiceDelegate<TService> CompileFactory<TService>(
45+
Type implementation)
46+
#endif
2747
{
2848
if (implementation == null)
2949
{
@@ -33,32 +53,56 @@ public static CreateServiceDelegate<TService> CompileFactory<TService>(Type impl
3353
return s => (TService)CompileFactory(implementation).Invoke(s)!;
3454
}
3555

36-
public static CreateServiceDelegate CompileFactory(Type type)
56+
#if NET6_0_OR_GREATER
57+
public static CreateServiceDelegate CompileFactory(
58+
[DynamicallyAccessedMembers(PublicConstructors)]
59+
Type type)
60+
#else
61+
public static CreateServiceDelegate CompileFactory(
62+
Type type)
63+
#endif
3764
{
3865
if (type is null)
3966
{
4067
throw new ArgumentNullException(nameof(type));
4168
}
4269

43-
return _cache.GetOrAdd(type, _ =>
44-
{
45-
var services = Expression.Parameter(typeof(IServiceProvider));
46-
var newInstance = CreateNewInstance(type, services);
47-
return Expression.Lambda<CreateServiceDelegate>(newInstance, services).Compile();
48-
});
70+
return _cache.GetOrAdd(
71+
type,
72+
_ =>
73+
{
74+
var services = Expression.Parameter(typeof(IServiceProvider));
75+
var newInstance = CreateNewInstance(type, services);
76+
return Expression.Lambda<CreateServiceDelegate>(newInstance, services).Compile();
77+
});
4978
}
5079

80+
#if NET6_0_OR_GREATER
81+
private static NewExpression CreateNewInstance(
82+
[DynamicallyAccessedMembers(PublicConstructors)]
83+
Type type,
84+
ParameterExpression services)
85+
#else
5186
private static NewExpression CreateNewInstance(
5287
Type type,
5388
ParameterExpression services)
89+
#endif
5490
{
5591
var constructor = ResolveConstructor(type);
5692
var arguments = CreateParameters(
57-
constructor.GetParameters(), services);
93+
constructor.GetParameters(),
94+
services);
5895
return Expression.New(constructor, arguments);
5996
}
6097

61-
internal static ConstructorInfo ResolveConstructor(Type type)
98+
#if NET6_0_OR_GREATER
99+
internal static ConstructorInfo ResolveConstructor(
100+
[DynamicallyAccessedMembers(PublicConstructors)]
101+
Type type)
102+
#else
103+
internal static ConstructorInfo ResolveConstructor(
104+
Type type)
105+
#endif
62106
{
63107
if (type is { IsClass: false, IsValueType: false } || type.IsAbstract)
64108
{
@@ -90,10 +134,11 @@ private static IEnumerable<Expression> CreateParameters(
90134
{
91135
foreach (var parameter in parameters)
92136
{
93-
yield return Expression.Convert(Expression.Call(
94-
services,
95-
_getService,
96-
Expression.Constant(parameter.ParameterType)),
137+
yield return Expression.Convert(
138+
Expression.Call(
139+
services,
140+
_getService,
141+
Expression.Constant(parameter.ParameterType)),
97142
parameter.ParameterType);
98143
}
99144
}
Lines changed: 58 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,16 @@
11
using System;
22
using System.Collections;
33
using System.Collections.Generic;
4-
using System.Linq;
5-
using System.Reflection;
4+
using System.Threading;
65

76
#nullable enable
87

98
namespace HotChocolate.Utilities;
109

1110
internal sealed class CombinedServiceProvider : IServiceProvider
1211
{
13-
private const string _methodNameAny = nameof(Enumerable.Any);
14-
private const string _methodNameConcat = nameof(Enumerable.Concat);
15-
private static readonly TypeInfo _enumerableTypeInfo = typeof(Enumerable).GetTypeInfo();
16-
private static readonly Type _genericIEnumerableType = typeof(IEnumerable<>);
17-
private static readonly TypeInfo _iEnumerableTypeInfo = typeof(IEnumerable).GetTypeInfo();
12+
private static List<object>? _buffer = new();
13+
private static readonly Type _enumerable = typeof(IEnumerable<>);
1814
private readonly IServiceProvider _first;
1915
private readonly IServiceProvider _second;
2016

@@ -31,58 +27,78 @@ public CombinedServiceProvider(IServiceProvider first, IServiceProvider second)
3127
throw new ArgumentNullException(nameof(serviceType));
3228
}
3329

34-
var serviceTypeInfo = serviceType.GetTypeInfo();
35-
36-
if (serviceTypeInfo.IsGenericType &&
37-
_iEnumerableTypeInfo.IsAssignableFrom(serviceTypeInfo) &&
38-
_genericIEnumerableType == serviceTypeInfo.GetGenericTypeDefinition())
30+
if (serviceType.IsGenericType && serviceType.GetGenericTypeDefinition() == _enumerable)
3931
{
40-
var firstResult = _first.GetService(serviceType);
41-
var secondResult = _second.GetService(serviceType);
42-
return Concat(serviceType, firstResult, secondResult);
32+
var elementType = serviceType.GetGenericArguments()[0];
33+
var firstResult = (IEnumerable?)_first.GetService(serviceType);
34+
var secondResult = (IEnumerable?)_second.GetService(serviceType);
35+
return Concat(elementType, firstResult, secondResult);
4336
}
4437

4538
return _first.GetService(serviceType) ?? _second.GetService(serviceType);
4639
}
4740

48-
private static bool Any(Type enumerableType, object enumerable)
41+
private object? Concat(
42+
Type elementType,
43+
IEnumerable? servicesFromA,
44+
IEnumerable? servicesFromB)
4945
{
50-
var genericArgumentType = enumerableType
51-
.GetTypeInfo()
52-
.GenericTypeArguments[0];
46+
if (servicesFromA is null)
47+
{
48+
return servicesFromB;
49+
}
5350

54-
var info = _enumerableTypeInfo
55-
.DeclaredMethods
56-
.First(m => m.Name == _methodNameAny && m.IsStatic && m.GetParameters().Length == 1)
57-
.MakeGenericMethod(genericArgumentType);
51+
if (servicesFromB is null)
52+
{
53+
return servicesFromA;
54+
}
5855

59-
return (bool)info.Invoke(null, new[] { enumerable })!;
60-
}
56+
var enumeratorA = servicesFromA.GetEnumerator();
57+
var enumeratorB = servicesFromB.GetEnumerator();
6158

62-
private static object? Concat(
63-
Type enumerableType,
64-
object? enumerableA,
65-
object? enumerableB)
66-
{
67-
if (enumerableA != null && Any(enumerableType, enumerableA))
59+
try
6860
{
69-
if (enumerableB != null && Any(enumerableType, enumerableB))
61+
var buffer = Interlocked.Exchange(ref _buffer, null) ?? new List<object>();
62+
63+
while (enumeratorA.MoveNext())
64+
{
65+
if (enumeratorA.Current is not null)
66+
{
67+
buffer.Add(enumeratorA.Current);
68+
}
69+
}
70+
71+
while (enumeratorB.MoveNext())
7072
{
71-
var genericArgumentType = enumerableType
72-
.GetTypeInfo()
73-
.GenericTypeArguments[0];
73+
if (enumeratorB.Current is not null)
74+
{
75+
buffer.Add(enumeratorB.Current);
76+
}
77+
}
7478

75-
var info = _enumerableTypeInfo
76-
.DeclaredMethods
77-
.First(m => m.Name == _methodNameConcat && m.IsStatic)
78-
.MakeGenericMethod(genericArgumentType);
79+
var array = Array.CreateInstance(elementType, buffer.Count);
7980

80-
return info.Invoke(null, new[] { enumerableA, enumerableB })!;
81+
for (var i = 0; i < buffer.Count; i++)
82+
{
83+
array.SetValue(buffer[i], i);
8184
}
8285

83-
return enumerableA;
86+
buffer.Clear();
87+
Interlocked.CompareExchange(ref buffer, buffer, null);
88+
89+
return array;
8490
}
91+
finally
92+
{
93+
if (enumeratorA is IDisposable disposableA)
94+
{
95+
disposableA.Dispose();
96+
}
8597

86-
return enumerableB;
98+
if (enumeratorB is IDisposable disposableB)
99+
{
100+
disposableB.Dispose();
101+
}
102+
}
87103
}
88104
}

src/HotChocolate/Utilities/src/Utilities/HotChocolate.Utilities.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
<Description>Contains internal helper classes and utilities used by the Hot Chocolate GraphQL type system and the GraphQL query execution engine.</Description>
88
</PropertyGroup>
99

10+
<PropertyGroup>
11+
<EnableTrimAnalyzer>true</EnableTrimAnalyzer>
12+
</PropertyGroup>
13+
1014
<ItemGroup>
1115
<InternalsVisibleTo Include="HotChocolate.AspNetCore" />
1216
<InternalsVisibleTo Include="HotChocolate.AspNetCore.Tests" />

src/HotChocolate/Utilities/src/Utilities/MiddlewareCompiler.cs

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Diagnostics.CodeAnalysis;
34
using System.Globalization;
45
using System.Linq;
56
using System.Linq.Expressions;
67
using System.Reflection;
78
using System.Threading.Tasks;
89
using HotChocolate.Utilities.Properties;
10+
#if NET6_0_OR_GREATER
11+
using static System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes;
12+
#endif
913

1014
namespace HotChocolate.Utilities;
1115

@@ -105,17 +109,29 @@ private static MethodCallExpression CreateInvokeMethodCall(
105109
UtilityResources.MiddlewareCompiler_ReturnTypeNotSupported);
106110
}
107111

112+
#if NET6_0_OR_GREATER
113+
private static NewExpression CreateMiddleware(
114+
[DynamicallyAccessedMembers(PublicConstructors)] Type middleware,
115+
IReadOnlyList<IParameterHandler> parameterHandlers)
116+
#else
108117
private static NewExpression CreateMiddleware(
109118
Type middleware,
110119
IReadOnlyList<IParameterHandler> parameterHandlers)
120+
#endif
111121
{
112122
var constructor = CreateConstructor(middleware);
113123
var arguments = CreateParameters(
114124
constructor.GetParameters(), parameterHandlers);
115125
return Expression.New(constructor, arguments);
116126
}
117127

118-
private static ConstructorInfo CreateConstructor(Type middleware)
128+
#if NET6_0_OR_GREATER
129+
private static ConstructorInfo CreateConstructor(
130+
[DynamicallyAccessedMembers(PublicConstructors)] Type middleware)
131+
#else
132+
private static ConstructorInfo CreateConstructor(
133+
Type middleware)
134+
#endif
119135
{
120136
var constructor =
121137
middleware.GetConstructors().SingleOrDefault(t => t.IsPublic);
@@ -154,13 +170,18 @@ private static List<Expression> CreateParameters(
154170
return arguments;
155171
}
156172

157-
private static MethodInfo? GetInvokeMethod(Type middlewareType) =>
158-
middlewareType.GetMethod("InvokeAsync") ??
159-
middlewareType.GetMethod("Invoke");
173+
#if NET6_0_OR_GREATER
174+
private static MethodInfo? GetInvokeMethod(
175+
[DynamicallyAccessedMembers(PublicMethods)] Type middlewareType)
176+
#else
177+
private static MethodInfo? GetInvokeMethod(
178+
Type middlewareType)
179+
#endif
180+
=> middlewareType.GetMethod("InvokeAsync") ?? middlewareType.GetMethod("Invoke");
160181

161182
private static class ExpressionHelper
162183
{
163-
public static async ValueTask AwaitTaskHelper(Task task) =>
164-
await task.ConfigureAwait(false);
184+
public static async ValueTask AwaitTaskHelper(Task task)
185+
=> await task.ConfigureAwait(false);
165186
}
166187
}

0 commit comments

Comments
 (0)