/// <summary> /// Configures the services and settings for the schema using the supplied configuration function. /// </summary> public void ConfigureServices() { // create the builder to guide the rest of the setup operations _options = new SchemaOptions(typeof(TSchema)); _schemaBuilder.TypeReferenceAdded += this.TypeReferenced_EventHandler; _options.TypeReferenceAdded += this.TypeReferenced_EventHandler; _configureOptions?.Invoke(_options); // register global directives to the schema foreach (var type in Constants.GlobalDirectives) { _options.AddGraphType(type); } // add execution assembly for auto loading of graph types if (_options.AutoRegisterLocalGraphEntities) { var assembly = Assembly.GetEntryAssembly(); _options.AddGraphAssembly(assembly); } // ensure some http processor is set if (_options.QueryHandler.HttpProcessorType == null) { if (_options.QueryHandler.AuthenticatedRequestsOnly) { _options.QueryHandler.HttpProcessorType = typeof(SecureGraphQLHttpProcessor <TSchema>); } else { _options.QueryHandler.HttpProcessorType = typeof(DefaultGraphQLHttpProcessor <TSchema>); } } // register the schema _serviceCollection.TryAddSingleton(this.BuildNewSchemaInstance); // setup default middleware for each required pipeline var queryPipelineHelper = new QueryExecutionPipelineHelper <TSchema>(_schemaBuilder.QueryExecutionPipeline); queryPipelineHelper.AddDefaultMiddlewareComponents(_options); var fieldPipelineHelper = new FieldExecutionPipelineHelper <TSchema>(_schemaBuilder.FieldExecutionPipeline); fieldPipelineHelper.AddDefaultMiddlewareComponents(_options); var authPipelineHelper = new FieldAuthorizationPipelineHelper <TSchema>(_schemaBuilder.FieldAuthorizationPipeline); authPipelineHelper.AddDefaultMiddlewareComponents(_options); // register the DI entries for each pipeline _serviceCollection.TryAddSingleton(this.CreatePipelineFactory(_schemaBuilder.FieldExecutionPipeline)); _serviceCollection.TryAddSingleton(this.CreatePipelineFactory(_schemaBuilder.FieldAuthorizationPipeline)); _serviceCollection.TryAddSingleton(this.CreatePipelineFactory(_schemaBuilder.QueryExecutionPipeline)); this.RegisterEngineComponents(); }
/// <summary> /// This method is called by the parent options just before it is added to the extensions /// collection. Use this method to do any sort of configuration, final default settings etc. /// This method represents the last opportunity for the extention options to modify its own required /// service collection before being incorporated with the DI container. /// </summary> /// <param name="options">The parent options which owns this extension.</param> public virtual void Configure(SchemaOptions options) { _primaryOptions = options; _primaryOptions.DeclarationOptions.AllowedOperations.Add(GraphCollection.Subscription); // enforce a default auth method for the server instance // if one was not set explicitly by the developer if (!_primaryOptions.AuthorizationOptions.Method.HasValue) { _primaryOptions.AuthorizationOptions.Method = REQUIRED_AUTH_METHOD; } // Security requirement for this component // -------------------------- // this component MUST use per request authorization // a subscription query is then checked before its registered // as opposed to when its executed var authMethod = _primaryOptions.AuthorizationOptions.Method; if (!authMethod.HasValue || authMethod != REQUIRED_AUTH_METHOD) { throw new ApolloSubscriptionServerException( $"Invalid Authorization Method. The default, apollo compliant, subscription server requires a \"{REQUIRED_AUTH_METHOD}\" " + $"authorization method. (Current authorization method is \"{_schemaBuilder.Options.AuthorizationOptions.Method}\")"); } // swap out the master providers for the ones that includes // support for the subscription action type if (!(GraphQLProviders.TemplateProvider is SubscriptionEnabledTemplateProvider)) { GraphQLProviders.TemplateProvider = new SubscriptionEnabledTemplateProvider(); } if (!(GraphQLProviders.GraphTypeMakerProvider is SubscriptionEnabledGraphTypeMakerProvider)) { GraphQLProviders.GraphTypeMakerProvider = new SubscriptionEnabledGraphTypeMakerProvider(); } // Update the query execution pipeline // ------------------------------------------ // wipe out the current execution pipeline and rebuild with subscription creation middleware injected _schemaBuilder.QueryExecutionPipeline.Clear(); var subscriptionQueryExecutionHelper = new SubscriptionQueryExecutionPipelineHelper <TSchema>(_schemaBuilder.QueryExecutionPipeline); subscriptionQueryExecutionHelper.AddDefaultMiddlewareComponents(_primaryOptions); // Update field execution pipeline // ----------------------------- // because the authorization method may have changed // rebuild the field execution pipeline as well. // This may happen when no method is declared for 'options.AuthorizationOptions.Method' // allowing the defaults to propegate during pipeline creation. // // The default for the basic server is "per field" // The required value for subscriptions is "per request" _schemaBuilder.FieldExecutionPipeline.Clear(); var fieldExecutionHelper = new FieldExecutionPipelineHelper <TSchema>(_schemaBuilder.FieldExecutionPipeline); fieldExecutionHelper.AddDefaultMiddlewareComponents(_primaryOptions); // the primary subscription options for the schema this.RequiredServices.Add(new ServiceDescriptor(typeof(SubscriptionServerOptions <TSchema>), this.SubscriptionOptions)); this.RequiredServices.Add( new ServiceDescriptor( typeof(ApolloMessageConverterFactory), typeof(ApolloMessageConverterFactory), ServiceLifetime.Singleton)); // add the needed apollo's classes as optional services // if the user has already added support for their own handlers // they will be safely ignored this.OptionalServices.Add( new ServiceDescriptor( typeof(ISubscriptionServer <TSchema>), this.CreateSubscriptionServer, ServiceLifetime.Singleton)); }