Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Introduce IOperationMessageListener #1010

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions src/Transports.AspNetCore/GraphQLHttpMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,7 @@ protected virtual IWebSocketConnection CreateWebSocketConnection(HttpContext htt
protected virtual IOperationMessageProcessor CreateMessageProcessor(IWebSocketConnection webSocketConnection, string subProtocol)
{
var authService = webSocketConnection.HttpContext.RequestServices.GetService<IWebSocketAuthenticationService>();
var listeners = webSocketConnection.HttpContext.RequestServices.GetServices<IOperationMessageListener>();

if (subProtocol == WebSockets.GraphQLWs.SubscriptionServer.SubProtocol)
{
Expand All @@ -691,7 +692,8 @@ protected virtual IOperationMessageProcessor CreateMessageProcessor(IWebSocketCo
_serializer,
_serviceScopeFactory,
this,
authService);
authService,
listeners);
}
else if (subProtocol == WebSockets.SubscriptionsTransportWs.SubscriptionServer.SubProtocol)
{
Expand All @@ -703,7 +705,8 @@ protected virtual IOperationMessageProcessor CreateMessageProcessor(IWebSocketCo
_serializer,
_serviceScopeFactory,
this,
authService);
authService,
listeners);
}

throw new ArgumentOutOfRangeException(nameof(subProtocol));
Expand Down
12 changes: 12 additions & 0 deletions src/Transports.AspNetCore/IOperationMessageListener.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace GraphQL.Server.Transports.AspNetCore;

/// <summary>
/// Allows to hook up into <see cref="BaseSubscriptionServer.OnMessageReceivedAsync(OperationMessage)"/>.
/// </summary>
public interface IOperationMessageListener
{
/// <summary>
/// This method is called at the very beginning of <see cref="BaseSubscriptionServer.OnMessageReceivedAsync(OperationMessage)"/>
/// </summary>
ValueTask ListenAsync(BaseSubscriptionServer subscriptionServer, OperationMessage message);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ namespace GraphQL.Server.Transports.AspNetCore.WebSockets.GraphQLWs;
public class SubscriptionServer : BaseSubscriptionServer
{
private readonly IWebSocketAuthenticationService? _authenticationService;
private readonly IOperationMessageListener[]? _listeners;

/// <summary>
/// The WebSocket sub-protocol used for this protocol.
Expand Down Expand Up @@ -51,6 +52,7 @@ public class SubscriptionServer : BaseSubscriptionServer
/// <param name="serviceScopeFactory">A <see cref="IServiceScopeFactory"/> to create service scopes for execution of GraphQL requests.</param>
/// <param name="userContextBuilder">The user context builder used during connection initialization.</param>
/// <param name="authenticationService">An optional service to authenticate connections.</param>
/// <param name="listeners">An optional collection of message listeners.</param>
public SubscriptionServer(
IWebSocketConnection connection,
GraphQLWebSocketOptions options,
Expand All @@ -59,19 +61,25 @@ public SubscriptionServer(
IGraphQLSerializer serializer,
IServiceScopeFactory serviceScopeFactory,
IUserContextBuilder userContextBuilder,
IWebSocketAuthenticationService? authenticationService = null)
IWebSocketAuthenticationService? authenticationService = null,
IEnumerable<IOperationMessageListener>? listeners = null)
: base(connection, options, authorizationOptions)
{
DocumentExecuter = executer ?? throw new ArgumentNullException(nameof(executer));
ServiceScopeFactory = serviceScopeFactory ?? throw new ArgumentNullException(nameof(serviceScopeFactory));
UserContextBuilder = userContextBuilder ?? throw new ArgumentNullException(nameof(userContextBuilder));
Serializer = serializer ?? throw new ArgumentNullException(nameof(serializer));
_authenticationService = authenticationService;
_listeners = listeners?.ToArray();
}

/// <inheritdoc/>
public override async Task OnMessageReceivedAsync(OperationMessage message)
{
if (_listeners != null)
foreach (var listener in _listeners)
await listener.ListenAsync(this, message);

if (message.Type == MessageType.Ping)
{
await OnPingAsync(message);
Expand Down Expand Up @@ -196,10 +204,9 @@ await Connection.SendMessageAsync(new OperationMessage
/// <inheritdoc/>
protected override async Task<ExecutionResult> ExecuteRequestAsync(OperationMessage message)
{
var request = Serializer.ReadNode<GraphQLRequest>(message.Payload);
#pragma warning disable CA2208 // Instantiate argument exceptions correctly
if (request == null)
throw new ArgumentNullException(nameof(message) + "." + nameof(OperationMessage.Payload));
var request = Serializer.ReadNode<GraphQLRequest>(message.Payload)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was analyzer warning about null check simplification.

?? throw new ArgumentNullException(nameof(message) + "." + nameof(OperationMessage.Payload));
#pragma warning restore CA2208 // Instantiate argument exceptions correctly
var scope = ServiceScopeFactory.CreateScope();
try
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ namespace GraphQL.Server.Transports.AspNetCore.WebSockets.SubscriptionsTransport
public class SubscriptionServer : BaseSubscriptionServer
{
private readonly IWebSocketAuthenticationService? _authenticationService;
private readonly IOperationMessageListener[]? _listeners;

/// <summary>
/// The WebSocket sub-protocol used for this protocol.
Expand Down Expand Up @@ -51,6 +52,7 @@ public class SubscriptionServer : BaseSubscriptionServer
/// <param name="serviceScopeFactory">A <see cref="IServiceScopeFactory"/> to create service scopes for execution of GraphQL requests.</param>
/// <param name="userContextBuilder">The user context builder used during connection initialization.</param>
/// <param name="authenticationService">An optional service to authenticate connections.</param>
/// <param name="listeners">An optional collection of message listeners.</param>
public SubscriptionServer(
IWebSocketConnection connection,
GraphQLWebSocketOptions options,
Expand All @@ -59,19 +61,25 @@ public SubscriptionServer(
IGraphQLSerializer serializer,
IServiceScopeFactory serviceScopeFactory,
IUserContextBuilder userContextBuilder,
IWebSocketAuthenticationService? authenticationService = null)
IWebSocketAuthenticationService? authenticationService = null,
IEnumerable<IOperationMessageListener>? listeners = null)
: base(connection, options, authorizationOptions)
{
DocumentExecuter = executer ?? throw new ArgumentNullException(nameof(executer));
ServiceScopeFactory = serviceScopeFactory ?? throw new ArgumentNullException(nameof(serviceScopeFactory));
UserContextBuilder = userContextBuilder ?? throw new ArgumentNullException(nameof(userContextBuilder));
Serializer = serializer ?? throw new ArgumentNullException(nameof(serializer));
_authenticationService = authenticationService;
_listeners = listeners?.ToArray();
}

/// <inheritdoc/>
public override async Task OnMessageReceivedAsync(OperationMessage message)
{
if (_listeners != null)
foreach (var listener in _listeners)
await listener.ListenAsync(this, message);

if (message.Type == MessageType.GQL_CONNECTION_TERMINATE)
{
await OnCloseConnectionAsync();
Expand Down Expand Up @@ -174,10 +182,9 @@ await Connection.SendMessageAsync(new OperationMessage
/// <inheritdoc/>
protected override async Task<ExecutionResult> ExecuteRequestAsync(OperationMessage message)
{
var request = Serializer.ReadNode<GraphQLRequest>(message.Payload);
#pragma warning disable CA2208 // Instantiate argument exceptions correctly
if (request == null)
throw new ArgumentNullException(nameof(message) + "." + nameof(OperationMessage.Payload));
var request = Serializer.ReadNode<GraphQLRequest>(message.Payload)
?? throw new ArgumentNullException(nameof(message) + "." + nameof(OperationMessage.Payload));
#pragma warning restore CA2208 // Instantiate argument exceptions correctly
var scope = ServiceScopeFactory.CreateScope();
try
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,10 @@ namespace GraphQL.Server.Transports.AspNetCore
string? AuthorizedPolicy { get; }
System.Collections.Generic.IEnumerable<string> AuthorizedRoles { get; }
}
public interface IOperationMessageListener
{
System.Threading.Tasks.ValueTask ListenAsync(GraphQL.Server.Transports.AspNetCore.WebSockets.BaseSubscriptionServer subscriptionServer, GraphQL.Transport.OperationMessage message);
}
public interface IUserContextBuilder
{
System.Threading.Tasks.ValueTask<System.Collections.Generic.IDictionary<string, object?>?> BuildUserContextAsync(Microsoft.AspNetCore.Http.HttpContext context, object? payload);
Expand Down Expand Up @@ -312,7 +316,7 @@ namespace GraphQL.Server.Transports.AspNetCore.WebSockets.GraphQLWs
}
public class SubscriptionServer : GraphQL.Server.Transports.AspNetCore.WebSockets.BaseSubscriptionServer
{
public SubscriptionServer(GraphQL.Server.Transports.AspNetCore.WebSockets.IWebSocketConnection connection, GraphQL.Server.Transports.AspNetCore.WebSockets.GraphQLWebSocketOptions options, GraphQL.Server.Transports.AspNetCore.IAuthorizationOptions authorizationOptions, GraphQL.IDocumentExecuter executer, GraphQL.IGraphQLSerializer serializer, Microsoft.Extensions.DependencyInjection.IServiceScopeFactory serviceScopeFactory, GraphQL.Server.Transports.AspNetCore.IUserContextBuilder userContextBuilder, GraphQL.Server.Transports.AspNetCore.WebSockets.IWebSocketAuthenticationService? authenticationService = null) { }
public SubscriptionServer(GraphQL.Server.Transports.AspNetCore.WebSockets.IWebSocketConnection connection, GraphQL.Server.Transports.AspNetCore.WebSockets.GraphQLWebSocketOptions options, GraphQL.Server.Transports.AspNetCore.IAuthorizationOptions authorizationOptions, GraphQL.IDocumentExecuter executer, GraphQL.IGraphQLSerializer serializer, Microsoft.Extensions.DependencyInjection.IServiceScopeFactory serviceScopeFactory, GraphQL.Server.Transports.AspNetCore.IUserContextBuilder userContextBuilder, GraphQL.Server.Transports.AspNetCore.WebSockets.IWebSocketAuthenticationService? authenticationService = null, System.Collections.Generic.IEnumerable<GraphQL.Server.Transports.AspNetCore.IOperationMessageListener>? listeners = null) { }
protected GraphQL.IDocumentExecuter DocumentExecuter { get; }
protected GraphQL.IGraphQLSerializer Serializer { get; }
protected Microsoft.Extensions.DependencyInjection.IServiceScopeFactory ServiceScopeFactory { get; }
Expand Down Expand Up @@ -350,7 +354,7 @@ namespace GraphQL.Server.Transports.AspNetCore.WebSockets.SubscriptionsTransport
}
public class SubscriptionServer : GraphQL.Server.Transports.AspNetCore.WebSockets.BaseSubscriptionServer
{
public SubscriptionServer(GraphQL.Server.Transports.AspNetCore.WebSockets.IWebSocketConnection connection, GraphQL.Server.Transports.AspNetCore.WebSockets.GraphQLWebSocketOptions options, GraphQL.Server.Transports.AspNetCore.IAuthorizationOptions authorizationOptions, GraphQL.IDocumentExecuter executer, GraphQL.IGraphQLSerializer serializer, Microsoft.Extensions.DependencyInjection.IServiceScopeFactory serviceScopeFactory, GraphQL.Server.Transports.AspNetCore.IUserContextBuilder userContextBuilder, GraphQL.Server.Transports.AspNetCore.WebSockets.IWebSocketAuthenticationService? authenticationService = null) { }
public SubscriptionServer(GraphQL.Server.Transports.AspNetCore.WebSockets.IWebSocketConnection connection, GraphQL.Server.Transports.AspNetCore.WebSockets.GraphQLWebSocketOptions options, GraphQL.Server.Transports.AspNetCore.IAuthorizationOptions authorizationOptions, GraphQL.IDocumentExecuter executer, GraphQL.IGraphQLSerializer serializer, Microsoft.Extensions.DependencyInjection.IServiceScopeFactory serviceScopeFactory, GraphQL.Server.Transports.AspNetCore.IUserContextBuilder userContextBuilder, GraphQL.Server.Transports.AspNetCore.WebSockets.IWebSocketAuthenticationService? authenticationService = null, System.Collections.Generic.IEnumerable<GraphQL.Server.Transports.AspNetCore.IOperationMessageListener>? listeners = null) { }
protected GraphQL.IDocumentExecuter DocumentExecuter { get; }
protected GraphQL.IGraphQLSerializer Serializer { get; }
protected Microsoft.Extensions.DependencyInjection.IServiceScopeFactory ServiceScopeFactory { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,10 @@ namespace GraphQL.Server.Transports.AspNetCore
{
System.Threading.CancellationToken ApplicationStopping { get; }
}
public interface IOperationMessageListener
{
System.Threading.Tasks.ValueTask ListenAsync(GraphQL.Server.Transports.AspNetCore.WebSockets.BaseSubscriptionServer subscriptionServer, GraphQL.Transport.OperationMessage message);
}
public interface IUserContextBuilder
{
System.Threading.Tasks.ValueTask<System.Collections.Generic.IDictionary<string, object?>?> BuildUserContextAsync(Microsoft.AspNetCore.Http.HttpContext context, object? payload);
Expand Down Expand Up @@ -330,7 +334,7 @@ namespace GraphQL.Server.Transports.AspNetCore.WebSockets.GraphQLWs
}
public class SubscriptionServer : GraphQL.Server.Transports.AspNetCore.WebSockets.BaseSubscriptionServer
{
public SubscriptionServer(GraphQL.Server.Transports.AspNetCore.WebSockets.IWebSocketConnection connection, GraphQL.Server.Transports.AspNetCore.WebSockets.GraphQLWebSocketOptions options, GraphQL.Server.Transports.AspNetCore.IAuthorizationOptions authorizationOptions, GraphQL.IDocumentExecuter executer, GraphQL.IGraphQLSerializer serializer, Microsoft.Extensions.DependencyInjection.IServiceScopeFactory serviceScopeFactory, GraphQL.Server.Transports.AspNetCore.IUserContextBuilder userContextBuilder, GraphQL.Server.Transports.AspNetCore.WebSockets.IWebSocketAuthenticationService? authenticationService = null) { }
public SubscriptionServer(GraphQL.Server.Transports.AspNetCore.WebSockets.IWebSocketConnection connection, GraphQL.Server.Transports.AspNetCore.WebSockets.GraphQLWebSocketOptions options, GraphQL.Server.Transports.AspNetCore.IAuthorizationOptions authorizationOptions, GraphQL.IDocumentExecuter executer, GraphQL.IGraphQLSerializer serializer, Microsoft.Extensions.DependencyInjection.IServiceScopeFactory serviceScopeFactory, GraphQL.Server.Transports.AspNetCore.IUserContextBuilder userContextBuilder, GraphQL.Server.Transports.AspNetCore.WebSockets.IWebSocketAuthenticationService? authenticationService = null, System.Collections.Generic.IEnumerable<GraphQL.Server.Transports.AspNetCore.IOperationMessageListener>? listeners = null) { }
protected GraphQL.IDocumentExecuter DocumentExecuter { get; }
protected GraphQL.IGraphQLSerializer Serializer { get; }
protected Microsoft.Extensions.DependencyInjection.IServiceScopeFactory ServiceScopeFactory { get; }
Expand Down Expand Up @@ -368,7 +372,7 @@ namespace GraphQL.Server.Transports.AspNetCore.WebSockets.SubscriptionsTransport
}
public class SubscriptionServer : GraphQL.Server.Transports.AspNetCore.WebSockets.BaseSubscriptionServer
{
public SubscriptionServer(GraphQL.Server.Transports.AspNetCore.WebSockets.IWebSocketConnection connection, GraphQL.Server.Transports.AspNetCore.WebSockets.GraphQLWebSocketOptions options, GraphQL.Server.Transports.AspNetCore.IAuthorizationOptions authorizationOptions, GraphQL.IDocumentExecuter executer, GraphQL.IGraphQLSerializer serializer, Microsoft.Extensions.DependencyInjection.IServiceScopeFactory serviceScopeFactory, GraphQL.Server.Transports.AspNetCore.IUserContextBuilder userContextBuilder, GraphQL.Server.Transports.AspNetCore.WebSockets.IWebSocketAuthenticationService? authenticationService = null) { }
public SubscriptionServer(GraphQL.Server.Transports.AspNetCore.WebSockets.IWebSocketConnection connection, GraphQL.Server.Transports.AspNetCore.WebSockets.GraphQLWebSocketOptions options, GraphQL.Server.Transports.AspNetCore.IAuthorizationOptions authorizationOptions, GraphQL.IDocumentExecuter executer, GraphQL.IGraphQLSerializer serializer, Microsoft.Extensions.DependencyInjection.IServiceScopeFactory serviceScopeFactory, GraphQL.Server.Transports.AspNetCore.IUserContextBuilder userContextBuilder, GraphQL.Server.Transports.AspNetCore.WebSockets.IWebSocketAuthenticationService? authenticationService = null, System.Collections.Generic.IEnumerable<GraphQL.Server.Transports.AspNetCore.IOperationMessageListener>? listeners = null) { }
protected GraphQL.IDocumentExecuter DocumentExecuter { get; }
protected GraphQL.IGraphQLSerializer Serializer { get; }
protected Microsoft.Extensions.DependencyInjection.IServiceScopeFactory ServiceScopeFactory { get; }
Expand Down