Skip to content

Commit 54db9b7

Browse files
authored
Merge pull request #25 from graphql-dotnet/fix-reflection-and-dependency-injection
Fix reflection and dependency injection
2 parents 573b877 + 3080549 commit 54db9b7

File tree

10 files changed

+103
-48
lines changed

10 files changed

+103
-48
lines changed

src/GraphQL.Conventions/Adapters/Engine/GraphQLEngine.cs

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Linq;
34
using System.Reflection;
45
using System.Threading;
56
using System.Threading.Tasks;
@@ -50,16 +51,19 @@ public INodeVisitor Validate(ValidationContext context)
5051

5152
private class WrappedDependencyInjector : IDependencyInjector
5253
{
54+
private readonly GraphQLEngine _engine;
55+
5356
private readonly Func<System.Type, object> _typeResolutionDelegate;
5457

55-
public WrappedDependencyInjector(Func<System.Type, object> typeResolutionDelegate)
58+
public WrappedDependencyInjector(GraphQLEngine engine, Func<System.Type, object> typeResolutionDelegate)
5659
{
60+
_engine = engine;
5761
_typeResolutionDelegate = typeResolutionDelegate;
5862
}
5963

6064
public object Resolve(System.Reflection.TypeInfo typeInfo)
6165
{
62-
return _typeResolutionDelegate(typeInfo.AsType());
66+
return _typeResolutionDelegate(typeInfo.AsType()) ?? _engine.CreateInstance(typeInfo.AsType());
6367
}
6468
}
6569

@@ -68,13 +72,13 @@ public GraphQLEngine(Func<System.Type, object> typeResolutionDelegate = null)
6872
_constructor = new SchemaConstructor<ISchema, IGraphType>(_graphTypeAdapter, _typeResolver);
6973
if (typeResolutionDelegate != null)
7074
{
71-
_typeResolver.DependencyInjector = new WrappedDependencyInjector(typeResolutionDelegate);
72-
_constructor.TypeResolutionDelegate = typeResolutionDelegate;
75+
_typeResolver.DependencyInjector = new WrappedDependencyInjector(this, typeResolutionDelegate);
76+
_constructor.TypeResolutionDelegate = type => typeResolutionDelegate(type) ?? CreateInstance(type);
7377
}
7478
else
7579
{
7680
_constructor.TypeResolutionDelegate = type =>
77-
_typeResolver?.DependencyInjector?.Resolve(type.GetTypeInfo()) ?? Activator.CreateInstance(type);
81+
_typeResolver?.DependencyInjector?.Resolve(type.GetTypeInfo()) ?? CreateInstance(type);
7882
}
7983
}
8084

@@ -228,5 +232,29 @@ internal IValidationResult Validate(string queryString)
228232
var document = _documentBuilder.Build(queryString);
229233
return _documentValidator.Validate(queryString, _schema, document);
230234
}
235+
236+
private object CreateInstance(System.Type type)
237+
{
238+
var typeInfo = type.GetTypeInfo();
239+
if (!typeInfo.IsAbstract && !typeInfo.ContainsGenericParameters)
240+
{
241+
var ctors = typeInfo.GetConstructors().ToList();
242+
if (ctors.All(ctor => ctor.GetParameters().Any()))
243+
{
244+
var ctor = ctors.FirstOrDefault();
245+
if (ctor == null)
246+
{
247+
return null;
248+
}
249+
var parameters = ctor.GetParameters();
250+
var parameterValues = parameters
251+
.Select(parameter => _constructor.TypeResolutionDelegate(parameter.ParameterType))
252+
.ToArray();
253+
return ctor.Invoke(parameterValues);
254+
}
255+
}
256+
257+
return Activator.CreateInstance(type);
258+
}
231259
}
232260
}

src/GraphQL.Conventions/Adapters/GraphTypeAdapter.cs

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,12 @@ namespace GraphQL.Conventions.Adapters
99
{
1010
public class GraphTypeAdapter : IGraphTypeAdapter<ISchema, IGraphType>
1111
{
12-
public static ILogger Logger { get; set; }
13-
1412
private readonly CachedRegistry<Type, IGraphType> _typeDescriptors = new CachedRegistry<Type, IGraphType>();
1513

1614
private readonly Dictionary<string, Type> _registeredScalarTypes = new Dictionary<string, Type>();
1715

1816
public ISchema DeriveSchema(GraphSchemaInfo schemaInfo)
1917
{
20-
Logger?.Trace($"Deriving Schema(Query={schemaInfo?.Query?.Name}, Mutation={schemaInfo?.Mutation?.Name})");
2118
var types = schemaInfo
2219
.Types
2320
.Where(t => !t.IsIgnored && !t.Interfaces.Any(iface => iface.IsIgnored))
@@ -27,11 +24,14 @@ public ISchema DeriveSchema(GraphSchemaInfo schemaInfo)
2724
DeriveType(type);
2825
}
2926
var interfaces = types
30-
.Where(t => t.IsInterfaceType && t.PossibleTypes.Any());
27+
.Where(t => t.IsInterfaceType && !t.IsInputType && t.PossibleTypes.Any())
28+
.GroupBy(t => t.Name)
29+
.Select(g => g.First());
3130
var possibleTypes = interfaces
3231
.Where(t => !t.IsIgnored)
3332
.SelectMany(t => t.PossibleTypes)
34-
.Distinct();
33+
.GroupBy(t => t.Name)
34+
.Select(g => g.First());
3535
var schema = new Schema(DeriveTypeFromTypeInfo)
3636
{
3737
Query = DeriveOperationType(schemaInfo.Query),
@@ -47,7 +47,6 @@ public ISchema DeriveSchema(GraphSchemaInfo schemaInfo)
4747

4848
public IGraphType DeriveType(GraphTypeInfo typeInfo)
4949
{
50-
Logger?.Trace($"Deriving Type={typeInfo?.Name}");
5150
var primitiveType = GetPrimitiveType(typeInfo);
5251
var graphType = primitiveType != null
5352
? WrapNonNullableType(typeInfo, Activator.CreateInstance(primitiveType) as GraphType)
@@ -57,7 +56,6 @@ public IGraphType DeriveType(GraphTypeInfo typeInfo)
5756

5857
public void RegisterScalarType<TType>(string name)
5958
{
60-
Logger?.Trace($"Registering Scalar(Name={name}, Type={typeof(TType).Name}");
6159
_registeredScalarTypes.Add(name, typeof(TType));
6260
}
6361

@@ -66,10 +64,8 @@ private IGraphType DeriveTypeFromTypeInfo(Type type)
6664
var graphType = _typeDescriptors.GetEntity(type);
6765
if (graphType != null)
6866
{
69-
Logger?.Trace($"Deriving representation for Type={type?.Name}");
7067
return graphType;
7168
}
72-
Logger?.Trace($"Instantiating representation for Type={type?.Name}");
7369
return (IGraphType)Activator.CreateInstance(type);
7470
}
7571

@@ -80,7 +76,6 @@ private IObjectGraphType DeriveOperationType(GraphTypeInfo typeInfo) =>
8076

8177
private FieldType DeriveField(GraphFieldInfo fieldInfo)
8278
{
83-
Logger?.Trace($"Deriving Field={fieldInfo?.Name}");
8479
return new FieldType
8580
{
8681
Name = fieldInfo.Name,
@@ -95,7 +90,6 @@ private FieldType DeriveField(GraphFieldInfo fieldInfo)
9590

9691
private QueryArgument DeriveArgument(GraphArgumentInfo argumentInfo)
9792
{
98-
Logger?.Trace($"Deriving Field={argumentInfo?.Name}");
9993
return new QueryArgument(GetType(argumentInfo.Type))
10094
{
10195
Name = argumentInfo.Name,
@@ -132,13 +126,11 @@ private Type GetPrimitiveType(GraphTypeInfo typeInfo)
132126
return typeof(Types.UriGraphType);
133127
default:
134128
Type type;
135-
Logger?.Trace($"Deriving PrimitiveType={typeInfo?.Name}");
136129
if (!string.IsNullOrWhiteSpace(typeInfo.Name) &&
137130
_registeredScalarTypes.TryGetValue(typeInfo.Name, out type))
138131
{
139132
return type;
140133
}
141-
Logger?.Warning($"Failed deriving PrimitiveType={typeInfo?.Name}");
142134
return null;
143135
}
144136
}
@@ -147,32 +139,26 @@ private IGraphType GetComplexType(GraphTypeInfo typeInfo)
147139
{
148140
if (typeInfo.IsInterfaceType)
149141
{
150-
Logger?.Trace($"Constructing InterfaceType={typeInfo?.Name}");
151142
return ConstructInterfaceType(typeInfo);
152143
}
153144
else if (typeInfo.IsEnumerationType)
154145
{
155-
Logger?.Trace($"Constructing EnumerationType={typeInfo?.Name}");
156146
return ConstructEnumerationType(typeInfo);
157147
}
158148
else if (typeInfo.IsUnionType)
159149
{
160-
Logger?.Trace($"Constructing UnionType={typeInfo?.Name}");
161150
return ConstructUnionType(typeInfo);
162151
}
163152
else if (typeInfo.IsListType)
164153
{
165-
Logger?.Trace($"Constructing ListType={typeInfo?.Name}");
166154
return ConstructListType(typeInfo);
167155
}
168156
else if (typeInfo.IsInputType)
169157
{
170-
Logger?.Trace($"Constructing InputType={typeInfo?.Name}");
171158
return ConstructInputType(typeInfo);
172159
}
173160
else if (typeInfo.IsOutputType)
174161
{
175-
Logger?.Trace($"Constructing OutputType={typeInfo?.Name}");
176162
return ConstructOutputType(typeInfo);
177163
}
178164
else
@@ -191,7 +177,6 @@ private IGraphType CacheType(GraphTypeInfo typeInfo, IGraphType graphType)
191177

192178
private TType CreateTypeInstance<TType>(Type type)
193179
{
194-
Logger?.Trace($"Creating TypeInstance={type?.Name}");
195180
var obj = Activator.CreateInstance(type);
196181
return obj is TType ? (TType)obj : default(TType);
197182
}
@@ -233,8 +218,14 @@ private IGraphType ConstructInterfaceType(GraphTypeInfo typeInfo)
233218
{
234219
return WrapNonNullableType(typeInfo, graphType);
235220
}
236-
foreach (var possibleType in typeInfo.PossibleTypes.Select(t => DeriveType(t) as IObjectGraphType))
221+
foreach (var possibleType in typeInfo
222+
.PossibleTypes
223+
.Select(t => DeriveType(t) as IObjectGraphType))
237224
{
225+
if (possibleType == null)
226+
{
227+
continue;
228+
}
238229
graphType.AddPossibleType(possibleType);
239230
}
240231
DeriveFields(typeInfo, graphType);

src/GraphQL.Conventions/Attributes/Collectors/AttributeCollector.cs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55

66
namespace GraphQL.Conventions.Attributes.Collectors
77
{
8+
public class AttributeCollector
9+
{
10+
public static Type ApplicationType { get; set; }
11+
}
12+
813
public class AttributeCollector<TAttribute>
914
where TAttribute : IAttribute
1015
{
@@ -48,6 +53,10 @@ public int CompareTo(WrappedAttribute other)
4853
public AttributeCollector()
4954
{
5055
DiscoverDefaultAttributes();
56+
if (AttributeCollector.ApplicationType != null)
57+
{
58+
DiscoverDefaultAttributes(AttributeCollector.ApplicationType);
59+
}
5160
}
5261

5362
public List<TAttribute> CollectAttributes(ICustomAttributeProvider obj)
@@ -60,6 +69,10 @@ public List<TAttribute> CollectAttributes(ICustomAttributeProvider obj)
6069

6170
protected void AddDefaultAttributes(params TAttribute[] defaultAttributes)
6271
{
72+
if (_defaultAttributes == null)
73+
{
74+
_defaultAttributes = new List<TAttribute>();
75+
}
6376
_defaultAttributes.AddRange(defaultAttributes);
6477
}
6578

@@ -81,11 +94,12 @@ private void DiscoverDefaultAttributes(Type assemblyType = null)
8194
}
8295

8396
var assembly = assemblyType.GetTypeInfo().Assembly;
84-
_defaultAttributes = assembly
97+
var defaultAttributes = assembly
8598
.GetTypes()
8699
.Where(type => IsDefaultAttribute(type) && IsTAttribute(type))
87100
.Select(type => (TAttribute)Activator.CreateInstance(type))
88-
.ToList();
101+
.ToArray();
102+
AddDefaultAttributes(defaultAttributes);
89103
}
90104

91105
private void DiscoverDefaultAttributes()

src/GraphQL.Conventions/Builders/SchemaConstructor.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public TSchemaType Build<TSchema>() =>
3636
Build(typeof(TSchema).GetTypeInfo());
3737

3838
public TSchemaType Build(params Type[] schemaTypes) =>
39-
Build(schemaTypes?.Select(type => type.GetTypeInfo()).ToArray());
39+
Build(schemaTypes?.Select(type => type?.GetTypeInfo()).ToArray());
4040

4141
public TSchemaType Build(params TypeInfo[] schemaTypes)
4242
{
@@ -56,7 +56,7 @@ public TSchemaType Build(params TypeInfo[] schemaTypes)
5656
{
5757
if (schemaInfo.Query != null)
5858
{
59-
schemaInfo.Query.Fields.AddRange(RemoveDuplicateViewers(additionalSchemaInfo.Query.Fields));
59+
schemaInfo.Query.Fields.AddRange(RemoveDuplicateViewers(additionalSchemaInfo.Query?.Fields));
6060
schemaInfo.Query.Fields = schemaInfo.Query.Fields.OrderBy(f => f.Name).ToList();
6161
}
6262
else
@@ -66,7 +66,7 @@ public TSchemaType Build(params TypeInfo[] schemaTypes)
6666

6767
if (schemaInfo.Mutation != null)
6868
{
69-
schemaInfo.Mutation.Fields.AddRange(RemoveDuplicateViewers(additionalSchemaInfo.Mutation.Fields));
69+
schemaInfo.Mutation.Fields.AddRange(RemoveDuplicateViewers(additionalSchemaInfo.Mutation?.Fields));
7070
schemaInfo.Mutation.Fields = schemaInfo.Mutation.Fields.OrderBy(f => f.Name).ToList();
7171
}
7272
else
@@ -76,7 +76,7 @@ public TSchemaType Build(params TypeInfo[] schemaTypes)
7676

7777
if (schemaInfo.Subscription != null)
7878
{
79-
schemaInfo.Subscription.Fields.AddRange(RemoveDuplicateViewers(additionalSchemaInfo.Subscription.Fields));
79+
schemaInfo.Subscription.Fields.AddRange(RemoveDuplicateViewers(additionalSchemaInfo.Subscription?.Fields));
8080
schemaInfo.Subscription.Fields = schemaInfo.Subscription.Fields.OrderBy(f => f.Name).ToList();
8181
}
8282
else
@@ -117,7 +117,7 @@ private IEnumerable<GraphFieldInfo> RemoveDuplicateViewers(IEnumerable<GraphFiel
117117
typeof(ImplementViewerAttribute.SubscriptionViewerReferrer),
118118
};
119119

120-
foreach (var field in fields)
120+
foreach (var field in fields ?? new List<GraphFieldInfo>())
121121
{
122122
if (field.Name == "viewer" &&
123123
registeredViewerClasses.Contains(field.DeclaringType.TypeRepresentation.AsType()))

src/GraphQL.Conventions/CommonAssemblyInfo.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
[assembly: AssemblyProduct("GraphQL.Conventions")]
88
[assembly: AssemblyCopyright("Copyright 2016-2017 Tommy Lillehagen. All rights reserved.")]
99
[assembly: AssemblyTrademark("")]
10-
[assembly: AssemblyVersion("1.1.1.0")]
11-
[assembly: AssemblyFileVersion("1.1.1.0")]
12-
[assembly: AssemblyInformationalVersion("1.1.1.0")]
10+
[assembly: AssemblyVersion("1.1.2.0")]
11+
[assembly: AssemblyFileVersion("1.1.2.0")]
12+
[assembly: AssemblyInformationalVersion("1.1.2.0")]
1313
[assembly: CLSCompliant(false)]
1414

1515
[assembly: InternalsVisibleTo("GraphQL.Conventions.Tests")]

src/GraphQL.Conventions/Handlers/ExecutionFilterAttributeHandler.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,13 @@ private void ResolveArgument(GraphArgumentInfo argument, IResolutionContext reso
4747
{
4848
object obj;
4949
var argumentType = (TypeInfo)argument.Type.AttributeProvider;
50-
if (argumentType.AsType() == typeof(IResolutionContext))
50+
if (argumentType.AsType() == typeof(IResolutionContext) ||
51+
argumentType.ImplementedInterfaces.Any(iface => iface == typeof(IResolutionContext)))
5152
{
5253
obj = resolutionContext;
5354
}
54-
else if (argumentType.AsType() == typeof(IUserContext))
55+
else if (argumentType.AsType() == typeof(IUserContext) ||
56+
argumentType.ImplementedInterfaces.Any(iface => iface == typeof(IUserContext)))
5557
{
5658
obj = resolutionContext.UserContext;
5759
}

src/GraphQL.Conventions/Handlers/MetaDataAttributeHandler.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ class MetaDataAttributeHandler<TAttribute>
1515
private readonly AttributeCollector<IExecutionFilterAttribute> _executionFilterCollector =
1616
new AttributeCollector<IExecutionFilterAttribute>();
1717

18+
public bool HasAttribute<T>(ICustomAttributeProvider obj)
19+
{
20+
var attributes = _collector.CollectAttributes(obj);
21+
return attributes.Any(attr => attr.GetType() == typeof(T));
22+
}
23+
1824
public void DeriveMetaData(GraphEntityInfo entity, ICustomAttributeProvider obj)
1925
{
2026
var attributes = _collector.CollectAttributes(obj);

src/GraphQL.Conventions/Types/Descriptors/GraphTypeInfo.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public GraphTypeInfo(ITypeResolver typeResolver, TypeInfo type)
5050

5151
public List<GraphTypeInfo> PossibleTypes => _possibleTypes;
5252

53-
public List<GraphTypeInfo> UnionTypes => PossibleTypes;
53+
public List<GraphTypeInfo> UnionTypes => IsUnionType ? PossibleTypes : new List<GraphTypeInfo>();
5454

5555
public List<GraphFieldInfo> Fields { get; internal set; } = new List<GraphFieldInfo>();
5656

0 commit comments

Comments
 (0)