From c70fe96855171d2cee34d67851b9f839f4338369 Mon Sep 17 00:00:00 2001 From: Pekka Heikura Date: Thu, 9 May 2019 21:17:41 +0300 Subject: [PATCH] Remove Schema from execution options in favor of GetSchema (#201) * Remove Schema from execution options in favor of GetSchema * Fix typo in doc --- dev/graphql.dev.chat.web/Startup.cs | 3 ++- docs/2-server/3-graphql-ws.md | 2 +- src/graphql.server/ExecutionOptions.cs | 9 +++++++-- src/graphql.server/QueryStreamService.cs | 5 +++-- .../ServiceCollectionExtensions.cs | 5 +++-- .../SignalRServerBuilderExtensions.cs | 2 +- .../webSockets/GraphQLWSProtocol.cs | 4 ++++ .../webSockets/IMessageContextAccessor.cs | 12 ++++++++++++ .../webSockets/WebSocketServer.cs | 5 +---- src/graphql/Parser.cs | 2 +- tests/graphql.server.tests.host/Startup.cs | 2 +- .../webSockets/GraphQLWSProtocolFacts.cs | 17 ++++++++++++----- 12 files changed, 48 insertions(+), 20 deletions(-) create mode 100644 src/graphql.server/webSockets/IMessageContextAccessor.cs diff --git a/dev/graphql.dev.chat.web/Startup.cs b/dev/graphql.dev.chat.web/Startup.cs index ef9e1ff70..860e79c5c 100644 --- a/dev/graphql.dev.chat.web/Startup.cs +++ b/dev/graphql.dev.chat.web/Startup.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using GraphQL.Server.Ui.Playground; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; @@ -39,7 +40,7 @@ public void ConfigureServices(IServiceCollection services) services.AddTankaExecutionOptions() .Configure((options, schema) => { - options.Schema = schema; + options.GetSchema = query => new ValueTask(schema); }); // signalr server diff --git a/docs/2-server/3-graphql-ws.md b/docs/2-server/3-graphql-ws.md index 9f34d097c..7c50f7761 100644 --- a/docs/2-server/3-graphql-ws.md +++ b/docs/2-server/3-graphql-ws.md @@ -42,7 +42,7 @@ configure this behavior with your own logic. ```csharp services.AddTankaWebSocketServerWithTracing() - .Configure( + .Configure( (options, authentication) => options.AcceptAsync = async context => { var token = context.Message.Payload.SelectToken("authToken"); diff --git a/src/graphql.server/ExecutionOptions.cs b/src/graphql.server/ExecutionOptions.cs index f40dba5b3..58516500b 100644 --- a/src/graphql.server/ExecutionOptions.cs +++ b/src/graphql.server/ExecutionOptions.cs @@ -1,9 +1,14 @@ -using tanka.graphql.type; +using System; +using System.Threading.Tasks; +using tanka.graphql.requests; +using tanka.graphql.type; namespace tanka.graphql.server { public class ExecutionOptions { - public ISchema Schema { get; set; } + public Func> GetSchema { get; set; } + + //public ISchema Schema { get; set; } } } \ No newline at end of file diff --git a/src/graphql.server/QueryStreamService.cs b/src/graphql.server/QueryStreamService.cs index 23386c7e7..6e747f805 100644 --- a/src/graphql.server/QueryStreamService.cs +++ b/src/graphql.server/QueryStreamService.cs @@ -37,10 +37,11 @@ public async Task QueryAsync( { _logger.Query(query); var serviceOptions = _optionsMonitor.CurrentValue; - var document = await Parser.ParseDocumentAsync(query.Query); + var document = Parser.ParseDocument(query.Query); + var schema = await serviceOptions.GetSchema(query); var executionOptions = new graphql.ExecutionOptions { - Schema = serviceOptions.Schema, + Schema = schema, Document = document, OperationName = query.OperationName, VariableValues = query.Variables, diff --git a/src/graphql.server/ServiceCollectionExtensions.cs b/src/graphql.server/ServiceCollectionExtensions.cs index a991ebc81..bd76506e7 100644 --- a/src/graphql.server/ServiceCollectionExtensions.cs +++ b/src/graphql.server/ServiceCollectionExtensions.cs @@ -35,8 +35,9 @@ public static OptionsBuilder AddTankaWebSocketServerWi public static OptionsBuilder AddTankaWebSocketServer(this IServiceCollection services) { services.AddSingleton(); - services.TryAddTransient(); - services.TryAddTransient(); + services.TryAddScoped(); + services.TryAddScoped(); + services.TryAddScoped(); return services.AddOptions(); } diff --git a/src/graphql.server/SignalRServerBuilderExtensions.cs b/src/graphql.server/SignalRServerBuilderExtensions.cs index 1a07aba1f..74a901dd1 100644 --- a/src/graphql.server/SignalRServerBuilderExtensions.cs +++ b/src/graphql.server/SignalRServerBuilderExtensions.cs @@ -32,7 +32,7 @@ public static ISignalRServerBuilder AddTankaServerHub( var services = builder.Services; services.AddSignalR(); - services.TryAddTransient(); + services.TryAddScoped(); return builder; } diff --git a/src/graphql.server/webSockets/GraphQLWSProtocol.cs b/src/graphql.server/webSockets/GraphQLWSProtocol.cs index e97b4482b..80cfdc10d 100644 --- a/src/graphql.server/webSockets/GraphQLWSProtocol.cs +++ b/src/graphql.server/webSockets/GraphQLWSProtocol.cs @@ -18,15 +18,18 @@ public class GraphQLWSProtocol : IProtocolHandler { private readonly GraphQLWSProtocolOptions _options; private readonly IQueryStreamService _queryStreamService; + private readonly IMessageContextAccessor _messageContextAccessor; private readonly ILogger _logger; private readonly JsonSerializer _serializer; public GraphQLWSProtocol( IQueryStreamService queryStreamService, IOptions options, + IMessageContextAccessor messageContextAccessor, ILogger logger) { _queryStreamService = queryStreamService; + _messageContextAccessor = messageContextAccessor; _logger = logger; _options = options.Value; _serializer = JsonSerializer.CreateDefault(new JsonSerializerSettings @@ -45,6 +48,7 @@ public ValueTask Handle(MessageContext context) context.Message.Id, context.Message.Type); + _messageContextAccessor.Context = context; return context.Message.Type switch { MessageType.GQL_CONNECTION_INIT => HandleInitAsync(context), diff --git a/src/graphql.server/webSockets/IMessageContextAccessor.cs b/src/graphql.server/webSockets/IMessageContextAccessor.cs new file mode 100644 index 000000000..fe6eb93b6 --- /dev/null +++ b/src/graphql.server/webSockets/IMessageContextAccessor.cs @@ -0,0 +1,12 @@ +namespace tanka.graphql.server.webSockets +{ + public interface IMessageContextAccessor + { + MessageContext Context { get; set; } + } + + public class MessageContextAccessor : IMessageContextAccessor + { + public MessageContext Context { get; set; } + } +} \ No newline at end of file diff --git a/src/graphql.server/webSockets/WebSocketServer.cs b/src/graphql.server/webSockets/WebSocketServer.cs index 93d117fc1..5a90b432c 100644 --- a/src/graphql.server/webSockets/WebSocketServer.cs +++ b/src/graphql.server/webSockets/WebSocketServer.cs @@ -24,8 +24,6 @@ public WebSocketServer( public async Task ProcessRequestAsync(HttpContext context) { - MessageServer messageServer = null; - try { _logger.LogInformation($"Processing WebSocket: {context.TraceIdentifier}"); @@ -33,7 +31,7 @@ public async Task ProcessRequestAsync(HttpContext context) var protocol = context.RequestServices .GetRequiredService(); - messageServer = new SubscriptionServer(protocol); + MessageServer messageServer = new SubscriptionServer(protocol); Clients.TryAdd(context.Connection, messageServer); var run = messageServer.RunAsync(connection, context.RequestAborted); @@ -43,7 +41,6 @@ public async Task ProcessRequestAsync(HttpContext context) } catch (Exception e) { - messageServer?.Complete(e); _logger.LogError(e, $"Processing websocket failed: {context.TraceIdentifier}"); throw; } diff --git a/src/graphql/Parser.cs b/src/graphql/Parser.cs index ac34bfcb1..73472c713 100644 --- a/src/graphql/Parser.cs +++ b/src/graphql/Parser.cs @@ -25,7 +25,7 @@ public static GraphQLDocument ParseDocument(string document) /// public static Task ParseDocumentAsync(string document) { - return Task.Run(() => + return Task.Factory.StartNew(() => { var lexer = new Lexer(); var parser = new GraphQLParser.Parser(lexer); diff --git a/tests/graphql.server.tests.host/Startup.cs b/tests/graphql.server.tests.host/Startup.cs index c9bf1fd08..670f3dcff 100644 --- a/tests/graphql.server.tests.host/Startup.cs +++ b/tests/graphql.server.tests.host/Startup.cs @@ -110,7 +110,7 @@ type Subscription { // web socket server services.AddTankaExecutionOptions() - .Configure((options, schema) => options.Schema = schema); + .Configure((options, schema) => options.GetSchema = query => new ValueTask(schema)); services.AddTankaWebSocketServer(); services.AddSignalR(options => { options.EnableDetailedErrors = true; }) diff --git a/tests/graphql.server.tests/webSockets/GraphQLWSProtocolFacts.cs b/tests/graphql.server.tests/webSockets/GraphQLWSProtocolFacts.cs index 2aef7b161..7e8b65325 100644 --- a/tests/graphql.server.tests/webSockets/GraphQLWSProtocolFacts.cs +++ b/tests/graphql.server.tests/webSockets/GraphQLWSProtocolFacts.cs @@ -18,11 +18,13 @@ public class GraphQLWSProtocolFacts { private IOptions _options; private NullLogger _logger; + private MessageContextAccessor _accessor; public GraphQLWSProtocolFacts() { _options = Options.Create(new GraphQLWSProtocolOptions()); _logger = new NullLogger(); + _accessor = new MessageContextAccessor(); } protected ValueTask ReadWithTimeout( @@ -34,13 +36,18 @@ protected ValueTask ReadWithTimeout( return channel.Reader.ReadAsync(cts.Token); } + public GraphQLWSProtocol CreateSut(IQueryStreamService queryStreamService) + { + return new GraphQLWSProtocol(queryStreamService, _options, _accessor, _logger); + } + [Fact] public async Task Unknown() { /* Given */ var channel = Channel.CreateUnbounded(); var queryStreamService = Substitute.For(); - var sut = new GraphQLWSProtocol(queryStreamService, _options, _logger); + var sut = CreateSut(queryStreamService); var message = new OperationMessage { @@ -66,7 +73,7 @@ public async Task Init() /* Given */ var channel = Channel.CreateUnbounded(); var queryStreamService = Substitute.For(); - var sut = new GraphQLWSProtocol(queryStreamService, _options, _logger); + var sut = CreateSut(queryStreamService); var message = new OperationMessage { @@ -92,7 +99,7 @@ public async Task Terminate() /* Given */ var channel = Channel.CreateUnbounded(); var queryStreamService = Substitute.For(); - var sut = new GraphQLWSProtocol(queryStreamService, _options, _logger); + var sut = CreateSut(queryStreamService); var message = new OperationMessage { @@ -120,7 +127,7 @@ public async Task Start() .ReturnsForAnyArgs(new QueryStream(queryStream)); - var sut = new GraphQLWSProtocol(queryStreamService, _options, _logger); + var sut = CreateSut(queryStreamService); var message = new OperationMessage { @@ -150,7 +157,7 @@ public async Task Stop() queryStreamService.QueryAsync(null, default) .ReturnsForAnyArgs(new QueryStream(queryStream)); - var sut = new GraphQLWSProtocol(queryStreamService, _options, _logger); + var sut = CreateSut(queryStreamService); var message = new OperationMessage { Id = "1",