GraphQL.AspNetCore3 5.2.0

dotnet add package GraphQL.AspNetCore3 --version 5.2.0
NuGet\Install-Package GraphQL.AspNetCore3 -Version 5.2.0
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="GraphQL.AspNetCore3" Version="5.2.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add GraphQL.AspNetCore3 --version 5.2.0
#r "nuget: GraphQL.AspNetCore3, 5.2.0"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install GraphQL.AspNetCore3 as a Cake Addin
#addin nuget:?package=GraphQL.AspNetCore3&version=5.2.0

// Install GraphQL.AspNetCore3 as a Cake Tool
#tool nuget:?package=GraphQL.AspNetCore3&version=5.2.0

GraphQL.AspNetCore3

NuGet Coverage Status

This package is designed for ASP.Net Core (2.1 through 6.0) to facilitate easy set-up of GraphQL requests over HTTP. The code is designed to be used as middleware within the ASP.Net Core pipeline, serving GET, POST or WebSocket requests. GET requests process requests from the querystring. POST requests can be in the form of JSON requests, form submissions, or raw GraphQL strings. WebSocket requests can use the graphql-ws or graphql-transport-ws WebSocket sub-protocol, as defined in the apollographql/subscriptions-transport-ws and enisdenjo/graphql-ws respoitories, respectively. The graphql-subscriptions sub-protocol is not supported.

The middleware can be configured through the IApplicationBuilder or IEndpointRouteBuilder builder interfaces.

In addition, an ExecutionResultActionResult class is added for returning ExecutionResult instances directly from a controller action.

Authorization is also supported with the included AuthorizationValidationRule. It will scan GraphQL documents and validate that the schema and all referenced output graph types, fields of output graph types, and query arguments meet the specified policy and/or roles held by the authenticated user within the ASP.NET Core authorization framework. It does not validate any policies or roles specified for input graph types, fields of input graph types, or directives. It does not skip validation for fields that are marked with the @skip or @include directives.

See version history / migration notes for changes from previous versions.

Configuration

Typical configuration with HTTP middleware

First add the GraphQL.AspNetCore3 nuget package to your application. It requires GraphQL version 7.0.0 or a later.

Then update your Program.cs or Startup.cs to register the schema, the serialization engine, and optionally the HTTP middleware and WebSocket services. Configure WebSockets and GraphQL in the HTTP pipeline by calling UseWebSockets and UseGraphQL at the appropriate point. Below is a complete sample of a .NET 6 console app that hosts a GraphQL endpoint at http://localhost:5000/graphql:

Project file
<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="GraphQL.AspNetCore3" Version="5.0.0" />
  </ItemGroup>

</Project>
Program.cs file
using GraphQL;
using GraphQL.MicrosoftDI;
using GraphQL.SystemTextJson;
using GraphQL.AspNetCore3;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddGraphQL(b => b
    .AddAutoSchema<Query>()  // schema
    .AddSystemTextJson());   // serializer

var app = builder.Build();
app.UseDeveloperExceptionPage();
app.UseWebSockets();
app.UseGraphQL("/graphql");  // url to host GraphQL endpoint
await app.RunAsync();
Schema
public class Query
{
    public static string Hero() => "Luke Skywalker";
}
Sample request url
http://localhost:5000/graphql?query={hero}
Sample response
{"data":{"hero":"Luke Skywalker"}}

Configuration with endpoint routing

To use endpoint routing, call MapGraphQL from inside the endpoint configuration builder rather than UseGraphQL on the application builder. See below for the sample of the application builder code:

var app = builder.Build();
app.UseDeveloperExceptionPage();
app.UseRouting();
app.UseEndpoints(endpoints => {
    endpoints.MapGraphQL("graphql");
});
await app.RunAsync();

Configuration with a MVC controller

Although not recommended, you may set up a controller action to execute GraphQL requests. You will not need UseGraphQL or MapGraphQL in the application startup. Below is a very basic sample; a much more complete sample can be found in the ControllerSample project within this repository. Although technically possible, the sample does not include support for WebSocket requests.

HomeController.cs
public class HomeController : Controller
{
    private readonly IDocumentExecuter _documentExecuter;

    public TestController(IDocumentExecuter<ISchema> documentExecuter)
    {
        _documentExecuter = documentExecuter;
    }

    [HttpGet]
    public async Task<IActionResult> GraphQL(string query)
    {
        var result = await _documentExecuter.ExecuteAsync(new() {
            Query = query,
            RequestServices = HttpContext.RequestServices,
            CancellationToken = HttpContext.RequestAborted,
        });
        return new ExecutionResultActionResult(result);
    }
}

User context configuration

To set the user context to be used during the execution of GraphQL requests, call AddUserContextBuilder during the GraphQL service setup to set a delegate which will be called when the user context is built. Alternatively, you can register an IUserContextBuilder implementation to do the same.

Program.cs / Startup.cs
builder.Services.AddGraphQL(b => b
    .AddAutoSchema<Query>()
    .AddSystemTextJson()
    .AddUserContextBuilder(httpContext => new MyUserContext(httpContext));
MyUserContext.cs
public class MyUserContext : Dictionary<string, object?>
{
    public ClaimsPrincipal User { get; }

    public MyUserContext(HttpContext context) : base()
    {
        User = context.User;
    }
}

Authorization configuration

You can configure authorization for all GraphQL requests, or for individual graphs, fields and query arguments within your schema. Both can be used if desired.

Be sure to call app.UseAuthentication() and app.UseAuthorization() prior to the call to app.UseGraphQL(). For example:

app.UseAuthentication();
app.UseAuthorization();
app.UseWebSockets();
app.UseGraphQL("/graphql");
For all GraphQL requests (including introspection requests)

When calling UseGraphQL, specify options as necessary to enable authorization as required.

app.UseGraphQL("/graphql", config => {
    // require that the user be authenticated
    config.AuthorizationRequired = true;

    // require that the user be a member of at least one role listed
    config.AuthorizedRoles.Add("MyRole");
    config.AuthorizedRoles.Add("MyAlternateRole");

    // require that the user pass a specific authorization policy
    config.AuthorizedPolicy = "MyPolicy";
});

Once configured, the request is authorized prior to parsing of the document or accepting the WebSocket request. Since WebSocket requests from browsers cannot typically carry a HTTP Authorization header, for JWT Bearer authentication you may need to disable authorization requirements for WebSocket connections and instead install an authentication handler for connection requests. To do so, use set the WebSocketsRequireAuthorization property to false and register an IWebSocketAuthorizationService as a singleton within your dependency injection framework. Below is an example:

services.AddSingleton<IWebSocketAuthorizationService, MyAuthService>();

app.UseGraphQL("/graphql", config => {
    // require that the user be authenticated
    config.AuthorizationRequired = true;
});

class MyAuthService : IWebSocketAuthenticationService
{
    private readonly IGraphQLSerializer _serializer;

    public MyWSAuthService(IGraphQLSerializer serializer)
    {
        _serializer = serializer;
    }

    public async ValueTask<bool> AuthenticateAsync(IWebSocketConnection connection, OperationMessage operationMessage)
    {
        var payload = _serializer.ReadNode<Inputs>(operationMessage.Payload);
        if (payload?.TryGetValue("Authorization", out var value) ?? false) {
            ClaimsPrincipal user;
            // validate token here and set user
            connection.HttpContext.User = user;
            return true; // authentication successful
        }
        return false; // authentication failed
    }
}

You may also wish to use IWebSocketAuthenticationService to set the HttpContext.User property, even if you allow anonymous requests.

For individual graphs, fields and query arguments

To configure ASP.NET Core authorization for GraphQL, add the corresponding validation rule during GraphQL configuration, typically by calling .AddAuthorizationRule() as shown below:

builder.Services.AddGraphQL(b => b
    .AddAutoSchema<Query>()
    .AddSystemTextJson()
    .AddAuthorizationRule());

Both roles and policies are supported for output graph types, fields on output graph types, and query arguments. If multiple policies are specified, all must match; if multiple roles are specified, any one role must match. You may also use .Authorize() or the [Authorize] attribute to validate that the user has authenticated. You may also use .AllowAnonymous() and [AllowAnonymous] to allow fields to be returned to unauthenticated users within an graph that has an authorization requirement defined.

Please note that authorization rules do not apply to values returned within introspection requests, potentially leaking information about protected areas of the schema to unauthenticated users. You may use the ISchemaFilter to restrict what information is returned from introspection requests, but it will apply to both authenticated and unauthenticated users alike.

Introspection requests are allowed unless the schema has an authorization requirement set on it. The @skip and @include directives are honored, skipping authorization checks for fields skipped by @skip or @include.

Please note that if you use interfaces, validation might be executed against the graph field or the interface field, depending on the structure of the query. For instance:

{
  cat {
    # validates against Cat.Name
    name

    # validates against Animal.Name
    ... on Animal {
      name
    }
  }
}

Similarly for unions, validation occurs on the exact type that is queried. Be sure to carefully consider placement of authorization rules when using interfaces and unions, especially when some fields are marked with AllowAnonymous.

Custom authentication configuration for GET/POST requests

To provide custom authentication code, bypassing ASP.NET Core's authentication, derive from the GraphQLHttpMiddleware<T> class and override HandleAuthorizeAsync, setting HttpContext.User to an appropriate ClaimsPrincipal instance.

See 'Customizing middleware behavior' below for an example of deriving from GraphQLHttpMiddleware.

Authentication for WebSocket requests

Since WebSocket requests from browsers cannot typically carry a HTTP Authorization header, you will need to authorize requests via the ConnectionInit WebSocket message or carry the authorization token within the URL. Below is a sample of the former:

builder.Services.AddGraphQL(b => b
    .AddAutoSchema<Query>()
    .AddSystemTextJson()
    .AddAuthorizationRule()  // not required for endpoint authorization
    .AddWebSocketAuthentication<MyAuthService>());

app.UseGraphQL("/graphql", config =>
{
    // require that the user be authenticated
    config.AuthorizationRequired = true;
});

class MyAuthService : IWebSocketAuthenticationService
{
    private readonly IGraphQLSerializer _serializer;

    public MyAuthService(IGraphQLSerializer serializer)
    {
        _serializer = serializer;
    }

    public async ValueTask<bool> AuthenticateAsync(IWebSocketConnection connection, OperationMessage operationMessage)
    {
        // read payload of ConnectionInit message and look for an "Authorization" entry that starts with "Bearer "
        var payload = _serializer.ReadNode<Inputs>(operationMessage.Payload);
        if ((payload?.TryGetValue("Authorization", out var value) ?? false) && value is string valueString)
        {
            var user = ParseToken(valueString);
            if (user != null)
            {
                // set user and indicate authentication was successful
                connection.HttpContext.User = user;
                return true;
            }
        }
        return false; // authentication failed
    }

    private ClaimsPrincipal? ParseToken(string authorizationHeaderValue)
    {
        // parse header value and return user, or null if unable
    }
}

To authorize based on information within the query string, it is recommended to derive from GraphQLHttpMiddleware<T> and override InvokeAsync, setting HttpContext.User based on the query string parameters, and then calling base.InvokeAsync. Alternatively you may override HandleAuthorizeAsync which will execute for GET/POST requests, and HandleAuthorizeWebSocketConnectionAsync for WebSocket requests. Note that InvokeAsync will execute even if the protocol is disabled in the options via disabling HandleGet or similar; HandleAuthorizeAsync and HandleAuthorizeWebSocketConnectionAsync will not.

Authentication schemes

By default the role and policy requirements are validated against the current user as defined by HttpContext.User. This is typically set by ASP.NET Core's authentication middleware and is based on the default authentication scheme set during the call to AddAuthentication in Startup.cs. You may override this behavior by specifying a different authentication scheme via the AuthenticationSchemes option. For instance, if you wish to authenticate using JWT authentication when Cookie authentication is the default, you may specify the scheme as follows:

app.UseGraphQL("/graphql", config =>
{
    // specify a specific authentication scheme to use
    config.AuthenticationSchemes.Add(JwtBearerDefaults.AuthenticationScheme);
});

This will overwrite the HttpContext.User property when handling GraphQL requests, which will in turn set the IResolveFieldContext.User property to the same value (unless being overridden via an IWebSocketAuthenticationService implementation as shown above). So both endpoint authorization and field authorization will perform role and policy checks against the same authentication scheme.

UI configuration

This project does not include user interfaces, such as GraphiQL or Playground, but you can include references to the ones provided by the GraphQL Server repository which work well with ASP.Net Core 2.1+. Below is a list of the nuget packages offered:

Package Downloads NuGet Latest
GraphQL.Server.Ui.Altair Nuget Nuget
GraphQL.Server.Ui.Playground Nuget Nuget
GraphQL.Server.Ui.GraphiQL Nuget Nuget
GraphQL.Server.Ui.Voyager Nuget Nuget

Here is a sample of how this would be configured in your Program.cs file:

app.UseGraphQL("/graphql");

// add this:
app.UseGraphQLPlayground(
    new GraphQL.Server.Ui.Playground.PlaygroundOptions {
        GraphQLEndPoint = new PathString("/graphql"),
        SubscriptionsEndPoint = new PathString("/graphql"),
    },
    "/");   // url to host Playground at

await app.RunAsync();

CORS configuration

ASP.NET Core supports CORS requests independently of GraphQL, including CORS pre-flight requests. To configure your application for CORS requests, add AddCors() and UseCors() into the application pipeline.

builder.Services.AddCors();

app.UseCors(policy => {
    // configure default policy here
});

To configure GraphQL to use a named CORS policy, configure the application to use endpoint routing and call RequireCors() on the endpoint configuration builder.

// ...
builder.Services.AddRouting();
builder.Services.AddCors(builder => {
    // configure named and/or default policies here
});

var app = builder.Build();
app.UseDeveloperExceptionPage();
app.UseWebSockets();
app.UseRouting();
app.UseCors();
app.UseEndpoints(endpoints => {
    // configure the graphql endpoint with the specified CORS policy
    endpoints.MapGraphQL()
        .RequireCors("MyCorsPolicy");
});
await app.RunAsync();

Response compression

ASP.NET Core supports response compression independently of GraphQL, with brotli and gzip support automatically based on the compression formats listed as supported in the request headers. To configure your application for response compression, configure your Program/Startup file as follows:

// add and configure the service
builder.Services.AddResponseCompression(options => {
    options.EnableForHttps = true; //may lead to CRIME and BREACH attacks
    options.MimeTypes = new[] { "application/json", "application/graphql+json" };
})

// place this first/early in the pipeline
app.UseResponseCompression();

In order to compress GraphQL responses, the application/graphql+json content type must be added to the MimeTypes option. You may choose to enable other content types as well.

Please note that enabling response compression over HTTPS can lead to CRIME and BREACH attacks. These side-channel attacks typically affects sites that rely on cookies for authentication. Please read this and this for more details.

ASP.NET Core 2.1

You may choose to use the .NET Core 2.1 runtime or a .NET Framework runtime. This library has been tested with .NET Core 2.1 and .NET Framework 4.8.

One additional requirement is that you must add this code in your Startup.cs file:

services.AddHostApplicationLifetime();

You will also need to reference a serializer package such as GraphQL.NewtonsoftJson or GraphQL.SystemTextJson, as GraphQL.SystemTextJson is not included in this case.

Besides that requirement, all features are supported in exactly the same manner as when using ASP.NET Core 3.1+. You may find differences in the ASP.NET Core runtime, such as CORS implementation differences, which are outside the scope of this project.

Advanced configuration

For more advanced configurations, see the overloads and configuration options available for the various builder methods, listed below. Methods and properties contain XML comments to provide assistance while coding with Visual Studio.

Builder interface Method Description
IGraphQLBuilder AddUserContextBuilder Sets up a delegate to create the UserContext for each GraphQL request.
IApplicationBuilder UseGraphQL Adds the GraphQL middleware to the HTTP request pipeline.
IEndpointRouteBuilder MapGraphQL Adds the GraphQL middleware to the HTTP request pipeline.

A number of the methods contain optional parameters or configuration delegates to allow further customization. Please review the overloads of each method to determine which options are available. In addition, many methods have more descriptive XML comments than shown above.

Configuration options

Below are descriptions of the options available when registering the HTTP middleware or WebSocket handler. Note that the HTTP middleware options are configured via the UseGraphQL or MapGraphQL methods allowing for different options for each configured endpoint.

GraphQLHttpMiddlewareOptions
Property Description Default value
AuthorizationRequired Requires HttpContext.User to represent an authenticated user. False
AuthorizedPolicy If set, requires HttpContext.User to pass authorization of the specified policy.
AuthorizedRoles If set, requires HttpContext.User to be a member of any one of a list of roles.
EnableBatchedRequests Enables handling of batched GraphQL requests for POST requests when formatted as JSON. True
ExecuteBatchedRequestsInParallel Enables parallel execution of batched GraphQL requests. True
HandleGet Enables handling of GET requests. True
HandlePost Enables handling of POST requests. True
HandleWebSockets Enables handling of WebSockets requests. True
ReadExtensionsFromQueryString Enables reading extensions from the query string. True
ReadQueryStringOnPost Enables parsing the query string on POST requests. True
ReadVariablesFromQueryString Enables reading variables from the query string. True
ValidationErrorsReturnBadRequest When enabled, GraphQL requests with validation errors have the HTTP status code set to 400 Bad Request. True
WebSockets Returns a set of configuration properties for WebSocket connections.
GraphQLWebSocketOptions
Property Description Default value
ConnectionInitWaitTimeout The amount of time to wait for a GraphQL initialization packet before the connection is closed. 10 seconds
KeepAliveTimeout The amount of time to wait between sending keep-alive packets. 30 seconds
DisconnectionTimeout The amount of time to wait to attempt a graceful teardown of the WebSockets protocol. 10 seconds
DisconnectAfterErrorEvent Disconnects a subscription from the client if the subscription source dispatches an OnError event. True
DisconnectAfterAnyError Disconnects a subscription from the client there are any GraphQL errors during a subscription. False

Multi-schema configuration

You may use the generic versions of the various builder methods to map a URL to a particular schema.

var app = builder.Build();
app.UseDeveloperExceptionPage();
app.UseGraphQL<DogSchema>("/graphql/dogs");
app.UseGraphQL<CatSchema>("/graphql/cats");
await app.RunAsync();

Different global authorization settings for different transports (GET/POST/WebSockets)

You may register the same endpoint multiple times if necessary to configure GET connections with certain authorization options, and POST connections with other authorization options.

var app = builder.Build();
app.UseDeveloperExceptionPage();
app.UseGraphQL("/graphql", options => {
    options.HandleGet = true;
    options.HandlePost = false;
    options.HandleWebSockets = false;
    options.AuthorizationRequired = false;
});
app.UseGraphQL("/graphql", options => {
    options.HandleGet = false;
    options.HandlePost = true;
    options.HandleWebSockets = true;
    options.AuthorizationRequired = true;
});
await app.RunAsync();

Since POST and WebSockets can be used for query requests, it is recommended not to do the above, but instead add the authorization validation rule and add authorization metadata on the Mutation and Subscription portions of your schema, as shown below:

builder.Services.AddGraphQL(b => b
    .AddSchema<MySchema>()
    .AddSystemTextJson()
    .AddAuthorizationRule()); // add authorization validation rule

var app = builder.Build();
app.UseDeveloperExceptionPage();
app.UseGraphQL();
await app.RunAsync();

// demonstration of code-first schema; also possible with schema-first or type-first schemas
public class MySchema : Schema
{
    public MySchema(IServiceProvider provider, MyQuery query, MyMutation mutation) : base(provider)
    {
        Query = query;
        Mutation = mutation;

        mutation.Authorize(); // require authorization for any mutation request
    }
}

Customizing middleware behavior

GET/POST requests are handled directly by the GraphQLHttpMiddleware. For WebSocket requests an WebSocketConnection instance is instated to dispatching incoming messages and send outgoing messages. Depending on the WebSocket sub-protocols supported by the client, the proper implementation of IOperationMessageProcessor is instated to act as a state machine, processing incoming messages and sending outgoing messages through the WebSocketConnection instance.

GraphQLHttpMiddleware

The base middleware functionality is contained within GraphQLHttpMiddleware, with code to perform execution of GraphQL requests in the derived class GraphQLHttpMiddleware<TSchema>. The classes are organized as follows:

  • InvokeAsync is the entry point to the middleware. For WebSocket connection requests, execution is immediately passed to HandleWebSocketsAsync.
  • Methods that start with Handle are passed the HttpContext and RequestDelegate instance, and may handle the request or pass execution to the RequestDelegate thereby skipping this execution handler. This includes methods to handle execution of single or batch queries or returning error conditions.
  • Methods that start with Write are for writing responses to the output stream.
  • Methods that start with Execute are for executing GraphQL requests.

A list of methods are as follows:

Method Description
InvokeAsync Entry point of the middleware
HandleRequestAsync Handles a single GraphQL request.
HandleBatchRequestAsync Handles a batched GraphQL request.
HandleWebSocketAsync Handles a WebSocket connection request.
BuildUserContextAsync Builds the user context based on a HttpContext.
ExecuteRequestAsync Executes a GraphQL request.
ExecuteScopedRequestAsync Executes a GraphQL request with a scoped service provider.
SelectResponseContentType Selects a content-type header for the JSON-formatted GraphQL response.
WriteErrorResponseAsync Writes the specified error message as a JSON-formatted GraphQL response, with the specified HTTP status code.
WriteJsonResponseAsync Writes the specified object (usually a GraphQL response) as JSON to the HTTP response stream.
Error handling method Description
HandleBatchedRequestsNotSupportedAsync Writes a '400 Batched requests are not supported.' message to the output.
HandleContentTypeCouldNotBeParsedErrorAsync Writes a '415 Invalid Content-Type header: could not be parsed.' message to the output.
HandleDeserializationErrorAsync Writes a '400 JSON body text could not be parsed.' message to the output.
HandleInvalidContentTypeErrorAsync Writes a '415 Invalid Content-Type header: non-supported type.' message to the output.
HandleInvalidHttpMethodErrorAsync Indicates that an unsupported HTTP method was requested. Executes the next delegate in the chain by default.
HandleWebSocketSubProtocolNotSupportedAsync Writes a '400 Invalid WebSocket sub-protocol.' message to the output.
WebSocket handler classes

The WebSocket handling code is organized as follows:

Interface / Class Description
IWebSocketConnection Provides methods to a send a message to a client or close the connection.
IOperationMessageProcessor Handles incoming messages from the client.
GraphQLWebSocketOptions Provides configuration options for WebSocket connections.
WebSocketConnection Standard implementation of a message pump for OperationMessage messages across a WebSockets connection. Implements IWebSocketConnection and delivers messages to a specified IOperationMessageProcessor.
BaseSubscriptionServer Abstract implementation of IOperationMessageProcessor, a message handler for OperationMessage messages. Provides base functionality for managing subscriptions and requests.
GraphQLWs.SubscriptionServer Implementation of IOperationMessageProcessor for the graphql-transport-ws sub-protocol.
SubscriptionsTransportWs.SubscriptionServer Implementation of IOperationMessageProcessor for the graphql-ws sub-protocol.
IWebSocketAuthorizationService Allows authorization of GraphQL requests for WebSocket connections.

Typically if you wish to change functionality or support another sub-protocol you will need to perform the following:

  1. Derive from either SubscriptionServer class, modifying functionality as needed, or to support a new protocol, derive from BaseSubscriptionServer.
  2. Derive from GraphQLHttpMiddleware and override CreateMessageProcessor and/or SupportedWebSocketSubProtocols as needed.
  3. Change the app.AddGraphQL() call to use your custom middleware, being sure to include an instance of the options class that your middleware requires (typically GraphQLHttpMiddlewareOptions).

There exists a few additional classes to support the above. Please refer to the source code of GraphQLWs.SubscriptionServer if you are attempting to add support for another protocol.

Additional notes

Service scope

By default, a dependency injection service scope is created for each GraphQL execution in cases where it is possible that multiple GraphQL requests may be executing within the same service scope:

  1. A batched GraphQL request is executed.
  2. A GraphQL request over a WebSocket connection is executed.

However, field resolvers for child fields of subscription nodes will not by default execute with a service scope. Rather, the context.RequestServices property will contain a reference to a disposed service scope that cannot be used.

To solve this issue, please configure the scoped subscription execution strategy from the GraphQL.MicrosoftDI package as follows:

services.AddGraphQL(b => b
    .AddAutoSchema<Query>()
    .AddSystemTextJson()
    // configure queries for serial execution (optional)
    .AddExecutionStrategy<SerialExecutionStrategy>(OperationType.Query)
    // configure subscription field resolvers for scoped serial execution (parallel is optional)
    .AddScopedSubscriptionExecutionStrategy());

For single GET / POST requests, the service scope from the underlying HTTP context is used.

User context builder

The user context builder interface is executed only once, within the dependency injection service scope of the original HTTP request. For batched requests, the same user context instance is passed to each GraphQL execution. For WebSocket requests, the same user context instance is passed to each GraphQL subscription and data event resolver execution.

As such, do not create objects within the user context that rely on having the same dependency injection service scope as the field resolvers. Since WebSocket connections are long-lived, using scoped services within a user context builder will result in those scoped services having a matching long lifetime. You may wish to alleviate this by creating a service scope temporarily within your user context builder.

For applications that service multiple schemas, you may register IUserContextBuilder<TSchema> to create a user context for a specific schema. This is useful when you need to create a user context that is specific to a particular schema.

Mutations within GET request

For security reasons and pursuant to current recommendations, mutation GraphQL requests are rejected over HTTP GET connections. Derive from GraphQLHttpMiddleware and override ExecuteRequestAsync to prevent injection of the validation rules that enforce this behavior.

As would be expected, subscription requests are only allowed over WebSocket channels.

Samples

The following samples are provided to show how to integrate this project with various typical ASP.Net Core scenarios.

Sample project Description
AuthorizationSample Demonstrates a GraphQL server added to an ASP.NET Core web authentication-enabled template.
BasicSample Demonstrates the minimum required setup for a HTTP GraphQL server.
Chat A basic schema common to all samples; demonstrates queries, mutations and subscriptions.
ControllerSample Demonstrates using a controller action to serve GraphQL requests; does not support subscriptions.
CorsSample Demonstrates configuring a GraphQL endpoint to use a specified CORS policy.
EndpointRoutingSample Demonstrates configuring GraphQL endpoints through endpoint routing.
MultipleSchema Demonstrates multiple GraphQL endpoints served through a single project.
Net48Sample Demonstrates a GraphQL server running on .NET Framework 4.8 (or for linux machines, .NET Core 2.1)
PagesSample Demonstrates configuring GraphQL within a ASP.NET Core Pages project.

Credits

Glory to Jehovah, Lord of Lords and King of Kings, creator of Heaven and Earth, who through his Son Jesus Christ, has reedemed me to become a child of God. -Shane32

Product Compatible and additional computed target framework versions.
.NET net5.0 is compatible.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 is compatible.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 is compatible. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
5.2.0 3,013 2/6/2024
5.1.0 6,821 7/5/2023
5.0.0 10,832 8/16/2022
4.0.1 448 8/7/2022
3.0.0 6,793 5/6/2022
2.1.0 7,172 4/14/2022
1.0.0 568 3/31/2022