• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Shane32 / GraphQL.DI / 12282594933

11 Dec 2024 06:26PM UTC coverage: 92.889% (+0.5%) from 92.391%
12282594933

push

github

web-flow
Add support for IDisposable (#24)

* Add support for IDisposable

* update workflows

* update workflow

* Add tests

72 of 82 branches covered (87.8%)

Branch coverage included in aggregate %.

30 of 31 new or added lines in 3 files covered. (96.77%)

137 of 143 relevant lines covered (95.8%)

40.02 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.79
/src/GraphQL.DI/DIObjectGraphType.cs
1
using System.Diagnostics;
2
using System.Linq.Expressions;
3
using System.Reflection;
4
using GraphQL.Types;
5
using Microsoft.Extensions.DependencyInjection;
6

7
namespace GraphQL.DI;
8

9
/// <summary>
10
/// Wraps a <see cref="DIObjectGraphBase"/> graph type for use with GraphQL. This class should be registered as a singleton
11
/// within your dependency injection provider.
12
/// </summary>
13
public class DIObjectGraphType<TDIGraph> : DIObjectGraphType<TDIGraph, object> where TDIGraph : IDIObjectGraphBase<object>
14
{
15
}
16

17
/// <summary>
18
/// Wraps a <see cref="DIObjectGraphBase{TSource}"/> graph type for use with GraphQL. This class should be registered as a singleton
19
/// within your dependency injection provider.
20
/// </summary>
21
public class DIObjectGraphType<TDIGraph, TSource> : AutoRegisteringObjectGraphType<TSource>
22
    where TDIGraph : IDIObjectGraphBase<TSource>
23
{
24
    /// <inheritdoc/>
25
    protected override void ConfigureGraph()
26
    {
65✔
27
        // do not configure attributes set on TSource
28
        // base.ConfigureGraph();
29

30
        // configure attributes set on DIObject instead
31
        var name = typeof(TDIGraph).GraphQLName();
65✔
32
        if (name.EndsWith("Graph", StringComparison.Ordinal) && name.Length > 5)
65✔
33
            name = name.Substring(0, name.Length - 5);
2✔
34
        Name = name;
65✔
35
        Description ??= typeof(TDIGraph).Description();
65✔
36
        DeprecationReason ??= typeof(TDIGraph).ObsoleteMessage();
65✔
37
        var attributes = typeof(TDIGraph).GetCustomAttributes<GraphQLAttribute>();
65✔
38
        foreach (var attr in attributes) {
201✔
39
            attr.Modify(this);
2✔
40
        }
2✔
41
    }
65✔
42

43
    // only process methods declared directly on TDIGraph -- not anything declared on TSource
44
    /// <inheritdoc/>
45
    protected override IEnumerable<MemberInfo> GetRegisteredMembers()
46
    {
65✔
47
        // only methods are supported
48
        var methods = typeof(TDIGraph).GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly)
65✔
49
            .Where(x =>
65✔
50
                !x.ContainsGenericParameters &&               // exclude methods with open generics
181!
51
                !x.IsSpecialName &&                           // exclude methods generated for properties
181✔
52
                x.ReturnType != typeof(void) &&               // exclude methods which do not return a value
181✔
53
                x.ReturnType != typeof(Task) &&               // exclude methods which do not return a value
181✔
54
                x.GetBaseDefinition() == x &&                 // exclude methods which override an inherited class' method (e.g. GetHashCode)
181✔
55
                                                              // exclude methods generated for record types: bool Equals(TSourceType)
181✔
56
                !(x.Name == "Equals" && !x.IsStatic && x.GetParameters().Length == 1 && x.GetParameters()[0].ParameterType == typeof(TDIGraph) && x.ReturnType == typeof(bool)) &&
181✔
57
                x.Name != "<Clone>$");                        // exclude methods generated for record types
181✔
58
        return methods;
65✔
59
    }
65✔
60

61
    // each field resolver will build a new instance of DIObject
62
    /// <inheritdoc/>
63
    protected override LambdaExpression BuildMemberInstanceExpression(MemberInfo memberInfo)
64
    {
111✔
65
        // use an explicit type here rather than simply LambdaExpression
66
        Expression<Func<IResolveFieldContext, TDIGraph>> func;
67
        if (typeof(IDisposable).IsAssignableFrom(typeof(TDIGraph))) {
113✔
68
            func = (IResolveFieldContext context) => MemberInstanceDisposableFunc(context);
2✔
69
        } else {
111✔
70
            func = (IResolveFieldContext context) => MemberInstanceFunc(context);
109✔
71
        }
109✔
72
        return func;
111✔
73
    }
111✔
74

75
    /// <inheritdoc/>
76
    private static TDIGraph MemberInstanceFunc(IResolveFieldContext context)
77
    {
12✔
78
        // create a new instance of DIObject, filling in any constructor arguments from DI
79
        var graph = ActivatorUtilities.GetServiceOrCreateInstance<TDIGraph>(context.RequestServices ?? ThrowMissingRequestServicesException());
12!
80
        // set the context
81
        graph.Context = context;
12✔
82
        // return the object
83
        return graph;
12✔
84

NEW
85
        static IServiceProvider ThrowMissingRequestServicesException() => throw new MissingRequestServicesException();
×
86
    }
12✔
87

88
    /// <inheritdoc/>
89
    private static TDIGraph MemberInstanceDisposableFunc(IResolveFieldContext context)
90
    {
2✔
91
        // pull DIObject from dependency injection, as it is disposable and must be managed by DI
92
        var graph = (context.RequestServices ?? throw new MissingRequestServicesException()).GetService<TDIGraph>()
2!
93
            ?? throw new InvalidOperationException($"Could not resolve an instance of {typeof(TDIGraph).Name} from the service provider. DI graph types that implement IDisposable must be registered in the service provider.");
2✔
94
        // set the context
95
        graph.Context = context;
1✔
96
        // return the object
97
        return graph;
1✔
98
    }
1✔
99

100
    /// <inheritdoc/>
101
    protected override ArgumentInformation GetArgumentInformation<TParameterType>(FieldType fieldType, ParameterInfo parameterInfo)
102
    {
22✔
103
        var typeInformation = GetTypeInformation(parameterInfo);
22✔
104
        var argumentInfo = new ArgumentInformation(parameterInfo, typeof(TSource), fieldType, typeInformation);
22✔
105
        if (argumentInfo.ParameterInfo.ParameterType == typeof(IServiceProvider))
22✔
106
        {
3✔
107
            argumentInfo.SetDelegate(context => context.RequestServices ?? throw new MissingRequestServicesException());
6!
108
        }
3✔
109
        if (argumentInfo.ParameterInfo.Name == "source" && argumentInfo.ParameterInfo.ParameterType == typeof(TSource))
22✔
110
        {
2✔
111
            argumentInfo.SetDelegate(context => (TSource?)context.Source);
3✔
112
        }
2✔
113
        argumentInfo.ApplyAttributes();
22✔
114
        return argumentInfo;
21✔
115
    }
21✔
116
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc