/// <summary>
        /// Adds middleware specified by its type to the list of delegates that will be applied to the schema when invoking <see cref="IFieldMiddlewareBuilder.ApplyTo(ISchema)"/>.
        /// <br/><br/>
        /// Middleware will be created using the DI container obtained from the <see cref="Schema"/>.
        /// </summary>
        /// <param name="builder">Interface for connecting middlewares to a schema.</param>
        /// <param name="middleware">Middleware type.</param>
        /// <returns>Reference to the same <see cref="IFieldMiddlewareBuilder"/>.</returns>
        public static IFieldMiddlewareBuilder Use(this IFieldMiddlewareBuilder builder, System.Type middleware)
        {
            if (!typeof(IFieldMiddleware).IsAssignableFrom(middleware))
            {
                throw new ArgumentException($"Field middleware of type '{middleware.FullName}' must implement the {nameof(IFieldMiddleware)} interface", nameof(middleware));
            }

            return(builder.Use((schema, next) =>
            {
                if (schema == null)
                {
                    throw new InvalidOperationException("Schema is null. Schema required for resolving middlewares from DI container.");
                }

                // Not an ideal solution, but at least it allows to work with custom schemas which are not inherited from Schema type
                if (!(schema is IServiceProvider provider))
                {
                    throw new NotSupportedException($"'{schema.GetType().FullName}' should implement 'IServiceProvider' interface for resolving middlewares.");
                }

                var instance = (IFieldMiddleware)provider.GetService(middleware);
                if (instance == null)
                {
                    throw new InvalidOperationException($"Field middleware of type '{middleware.FullName}' must be registered in the DI container.");
                }

                return context => instance.Resolve(context, next);
            }));
        }
        public static IFieldMiddlewareBuilder Use(this IFieldMiddlewareBuilder builder, System.Type middleware)
        {
            return(builder.Use(next =>
            {
                var methods = middleware.GetMethods(BindingFlags.Instance | BindingFlags.Public);
                var invokeMethods = methods.Where(m => string.Equals(m.Name, InvokeMethodName, StringComparison.Ordinal)).ToArray();
                if (invokeMethods.Length > 1)
                {
                    throw new InvalidOperationException($"There should be only a single method named {InvokeMethodName}. Middleware actually has {invokeMethods.Length} methods.");
                }

                if (invokeMethods.Length == 0)
                {
                    throw new InvalidOperationException($"Could not find a method named {InvokeMethodName}. Middleware must have a public instance method named {InvokeMethodName}.");
                }

                var methodInfo = invokeMethods[0];
                if (!typeof(Task <object>).IsAssignableFrom(methodInfo.ReturnType))
                {
                    throw new InvalidOperationException($"The {InvokeMethodName} method should return a Task<object>.");
                }

                var parameters = methodInfo.GetParameters();
                if (parameters.Length != 2 || parameters[0].ParameterType != typeof(ResolveFieldContext) || parameters[1].ParameterType != typeof(FieldMiddlewareDelegate))
                {
                    throw new InvalidOperationException($"The {InvokeMethodName} method of middleware should take a parameter of type {nameof(ResolveFieldContext)} as the first parameter and a parameter of type {nameof(FieldMiddlewareDelegate)} as the second parameter.");
                }

                var instance = Activator.CreateInstance(middleware);

                return context => (Task <object>)methodInfo.Invoke(instance, new object[] { context, next });
            }));
        }
        /// <summary>
        /// Applies all delegates specified by the middleware builder to the schema.
        /// <br/><br/>
        /// When applying to the schema, modifies the resolver of each field of each graph type adding required behavior.
        /// Therefore, as a rule, this method should be called only once - during schema initialization.
        /// </summary>
        public void ApplyMiddleware(IFieldMiddlewareBuilder fieldMiddlewareBuilder)
        {
            var transform = (fieldMiddlewareBuilder ?? throw new ArgumentNullException(nameof(fieldMiddlewareBuilder))).Build();

            // allocation free optimization if no middlewares are defined
            if (transform != null)
            {
                ApplyMiddleware(transform);
            }
        }
 /// <summary>
 /// Adds middleware specified by its type to the list of delegates that will be applied to the schema when invoking <see cref="IFieldMiddlewareBuilder.ApplyTo(ISchema)"/>.
 /// <br/><br/>
 /// Middleware will be created using the DI container obtained from the <see cref="Schema"/>.
 /// </summary>
 /// <typeparam name="T">Middleware type.</typeparam>
 /// <param name="builder">Interface for connecting middlewares to a schema.</param>
 /// <returns>Reference to the same <see cref="IFieldMiddlewareBuilder"/>.</returns>
 public static IFieldMiddlewareBuilder Use <T>(this IFieldMiddlewareBuilder builder) where T : IFieldMiddleware => Use(builder, typeof(T));
 /// <summary>
 /// Adds the specified delegate to the list of delegates that will be applied to the schema when invoking <see cref="IFieldMiddlewareBuilder.ApplyTo(ISchema)"/>.
 /// <br/><br/>
 /// This is a compatibility shim when compiling delegates without schema specified.
 /// </summary>
 /// <param name="builder">Interface for connecting middlewares to a schema.</param>
 /// <param name="middleware">Middleware delegate.</param>
 /// <returns>Reference to the same <see cref="IFieldMiddlewareBuilder"/>.</returns>
 public static IFieldMiddlewareBuilder Use(this IFieldMiddlewareBuilder builder, Func <FieldMiddlewareDelegate, FieldMiddlewareDelegate> middleware)
 => builder.Use((_, next) => middleware(next));
 /// <summary>
 /// Adds middleware to the list of delegates that will be applied to the schema when invoking <see cref="IFieldMiddlewareBuilder.ApplyTo(ISchema)"/>.
 /// </summary>
 /// <param name="builder">Interface for connecting middlewares to a schema.</param>
 /// <param name="middleware">Middleware instance.</param>
 /// <returns>Reference to the same <see cref="IFieldMiddlewareBuilder"/>.</returns>
 public static IFieldMiddlewareBuilder Use(this IFieldMiddlewareBuilder builder, IFieldMiddleware middleware)
 => builder.Use(next => context => middleware.Resolve(context, next));
 public static IFieldMiddlewareBuilder Use <T>(this IFieldMiddlewareBuilder builder)
 {
     return(Use(builder, typeof(T)));
 }
 /// <summary>
 /// Adds middleware specified by its type to the list of delegates that will be applied to the schema when invoking <see cref="ApplyTo(ISchema)"/>.
 /// <br/><br/>
 /// Middleware will be created using the DI container obtained from the <see cref="Schema"/>.
 /// </summary>
 /// <param name="builder">Interface for connecting middlewares to a schema.</param>
 /// <param name="middleware">Middleware type.</param>
 /// <returns>Reference to the same <see cref="IFieldMiddlewareBuilder"/>.</returns>
 public static IFieldMiddlewareBuilder Use(this IFieldMiddlewareBuilder builder, System.Type middleware)
 {