{"id":13429490,"url":"https://github.com/graphql-dotnet/server","last_synced_at":"2025-05-15T04:06:14.388Z","repository":{"id":37251442,"uuid":"103694242","full_name":"graphql-dotnet/server","owner":"graphql-dotnet","description":"ASP.NET Core GraphQL Server","archived":false,"fork":false,"pushed_at":"2025-03-07T01:01:42.000Z","size":3107,"stargazers_count":589,"open_issues_count":16,"forks_count":162,"subscribers_count":22,"default_branch":"master","last_synced_at":"2025-04-15T01:58:44.981Z","etag":null,"topics":["aspnetcore","graphql","server"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/graphql-dotnet.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2017-09-15T19:32:39.000Z","updated_at":"2025-04-12T16:47:29.000Z","dependencies_parsed_at":"2023-02-14T00:01:19.878Z","dependency_job_id":"747f8f75-5041-437c-9274-125344c23282","html_url":"https://github.com/graphql-dotnet/server","commit_stats":null,"previous_names":[],"tags_count":45,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphql-dotnet%2Fserver","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphql-dotnet%2Fserver/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphql-dotnet%2Fserver/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graphql-dotnet%2Fserver/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/graphql-dotnet","download_url":"https://codeload.github.com/graphql-dotnet/server/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254270646,"owners_count":22042859,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aspnetcore","graphql","server"],"created_at":"2024-07-31T02:00:40.575Z","updated_at":"2025-05-15T04:06:09.372Z","avatar_url":"https://github.com/graphql-dotnet.png","language":"C#","funding_links":[],"categories":["Frameworks, Libraries and Tools","C\\#","框架, 库和工具","API"],"sub_categories":["API"],"readme":"# ASP.NET Core GraphQL Server driven by GraphQL.NET\n\n[![License](https://img.shields.io/github/license/graphql-dotnet/server)](LICENSE.md)\n[![codecov](https://codecov.io/gh/graphql-dotnet/server/branch/master/graph/badge.svg?token=ZBcVYq7hz4)](https://codecov.io/gh/graphql-dotnet/server)\n[![Nuget](https://img.shields.io/nuget/dt/GraphQL.Server.Transports.AspNetCore)](https://www.nuget.org/packages/GraphQL.Server.Transports.AspNetCore)\n[![Nuget](https://img.shields.io/nuget/v/GraphQL.Server.Transports.AspNetCore)](https://www.nuget.org/packages/GraphQL.Server.Transports.AspNetCore)\n[![GitHub Release Date](https://img.shields.io/github/release-date/graphql-dotnet/server?label=released)](https://github.com/graphql-dotnet/server/releases)\n[![GitHub commits since latest release (by date)](https://img.shields.io/github/commits-since/graphql-dotnet/server/latest?label=new+commits)](https://github.com/graphql-dotnet/server/commits/master)\n[![GitHub contributors](https://img.shields.io/github/contributors/graphql-dotnet/server)](https://github.com/graphql-dotnet/server/graphs/contributors)\n![Size](https://img.shields.io/github/repo-size/graphql-dotnet/server)\n\nGraphQL ASP.NET Core server on top of [GraphQL.NET](https://github.com/graphql-dotnet/graphql-dotnet).\nHTTP transport compatible with the [GraphQL over HTTP draft specification](https://github.com/graphql/graphql-over-http/blob/main/spec/GraphQLOverHTTP.md).\nWebSocket transport compatible with both [subscriptions-transport-ws](https://github.com/apollographql/subscriptions-transport-ws) and\n[graphql-ws](https://github.com/enisdenjo/graphql-ws) subscription protocols. The transport format of all messages is supposed to be JSON.\n\nProvides the following packages:\n\n| Package                                              | Downloads                                                                                                                                                                             | Version                                                                                                                                                                              | Description |\n|------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|\n| GraphQL.Server.All                                   | [![Nuget](https://img.shields.io/nuget/dt/GraphQL.Server.All)](https://www.nuget.org/packages/GraphQL.Server.All)                                                                     | [![Nuget](https://img.shields.io/nuget/v/GraphQL.Server.All)](https://www.nuget.org/packages/GraphQL.Server.All)                                                                     | Includes all the packages below, plus the `GraphQL.DataLoader` and `GraphQL.MemoryCache` packages |\n| GraphQL.Server.Transports.AspNetCore                 | [![Nuget](https://img.shields.io/nuget/dt/GraphQL.Server.Transports.AspNetCore)](https://www.nuget.org/packages/GraphQL.Server.Transports.AspNetCore)                                 | [![Nuget](https://img.shields.io/nuget/v/GraphQL.Server.Transports.AspNetCore)](https://www.nuget.org/packages/GraphQL.Server.Transports.AspNetCore)                                 | Provides GraphQL over HTTP/WebSocket server support on top of ASP.NET Core, plus authorization rule support |\n| GraphQL.Server.Ui.Altair                             | [![Nuget](https://img.shields.io/nuget/dt/GraphQL.Server.Ui.Altair)](https://www.nuget.org/packages/GraphQL.Server.Ui.Altair)                                                         | [![Nuget](https://img.shields.io/nuget/v/GraphQL.Server.Ui.Altair)](https://www.nuget.org/packages/GraphQL.Server.Ui.Altair)                                                         | Provides Altair UI middleware |\n| GraphQL.Server.Ui.Playground :warning:               | [![Nuget](https://img.shields.io/nuget/dt/GraphQL.Server.Ui.Playground)](https://www.nuget.org/packages/GraphQL.Server.Ui.Playground)                                                 | [![Nuget](https://img.shields.io/nuget/v/GraphQL.Server.Ui.Playground)](https://www.nuget.org/packages/GraphQL.Server.Ui.Playground)                                                 | Provides Playground UI middleware (deprecated) |\n| GraphQL.Server.Ui.GraphiQL                           | [![Nuget](https://img.shields.io/nuget/dt/GraphQL.Server.Ui.GraphiQL)](https://www.nuget.org/packages/GraphQL.Server.Ui.GraphiQL)                                                     | [![Nuget](https://img.shields.io/nuget/v/GraphQL.Server.Ui.GraphiQL)](https://www.nuget.org/packages/GraphQL.Server.Ui.GraphiQL)                                                     | Provides GraphiQL UI middleware |\n| GraphQL.Server.Ui.Voyager                            | [![Nuget](https://img.shields.io/nuget/dt/GraphQL.Server.Ui.Voyager)](https://www.nuget.org/packages/GraphQL.Server.Ui.Voyager)                                                       | [![Nuget](https://img.shields.io/nuget/v/GraphQL.Server.Ui.Voyager)](https://www.nuget.org/packages/GraphQL.Server.Ui.Voyager)                                                       | Provides Voyager UI middleware |\n\nYou can install the latest stable versions via [NuGet](https://www.nuget.org/packages/GraphQL.Server.Transports.AspNetCore/).\nAlso you can get all preview versions from [GitHub Packages](https://github.com/orgs/graphql-dotnet/packages?repo_name=server).\nNote that GitHub requires authentication to consume the feed. See more information [here](https://docs.github.com/en/free-pro-team@latest/packages/publishing-and-managing-packages/about-github-packages#authenticating-to-github-packages).\n\n| :warning: When upgrading from prior versions, please remove references to these old packages :warning: |\n|-|\n| GraphQL.Server.Core |\n| GraphQL.Server.Authentication.AspNetCore |\n| GraphQL.Server.Transports.AspNetCore.NewtonsoftJson |\n| GraphQL.Server.Transports.AspNetCore.SystemTextJson |\n| GraphQL.Server.Transports.Subscriptions.Abstractions |\n| GraphQL.Server.Transports.Subscriptions.WebSockets |\n| GraphQL.Server.Transports.WebSocktes |\n\n## Description\n\nThis package is designed for ASP.NET Core (2.1 through 9.0) to facilitate easy set-up of GraphQL requests\nover HTTP.  The code is designed to be used as middleware within the ASP.NET Core pipeline,\nserving GET, POST or WebSocket requests.  GET requests process requests from the query string.\nPOST requests can be in the form of JSON requests, form submissions, or raw GraphQL strings.\nForm submissions either accepts `query`, `operationName`, `variables` and `extensions` parameters,\nor `operations` and `map` parameters along with file uploads as defined in the\n[GraphQL multipart request spec](https://github.com/jaydenseric/graphql-multipart-request-spec).\nWebSocket requests can use the `graphql-ws` or `graphql-transport-ws` WebSocket sub-protocol,\nas defined in the [apollographql/subscriptions-transport-ws](https://github.com/apollographql/subscriptions-transport-ws)\nand [enisdenjo/graphql-ws](https://github.com/enisdenjo/graphql-ws) repositories, respectively.\n\nThe middleware can be configured through the `IApplicationBuilder` or `IEndpointRouteBuilder`\nbuilder interfaces.  In addition, an `ExecutionResultActionResult` class is added for returning\n`ExecutionResult` instances directly from a controller action.\n\nAuthorization is also supported with the included `AuthorizationValidationRule`.  It will\nscan GraphQL documents and validate that the schema and all referenced output graph types, fields of\noutput graph types, and query arguments meet the specified policy and/or roles held by the\nauthenticated user within the ASP.NET Core authorization framework.  It does not validate\nany policies or roles specified for input graph types, fields of input graph types, or\ndirectives.  It skips validations for fields or fragments that are marked with the `@skip` or\n`@include` directives.\n\n### Migration from older version\n\n- [v7 to v8 migration notes](docs/migration/migration8.md)\n- [v6 to v7 migration notes](docs/migration/migration7.md)\n\n## Configuration\n\n### Typical configuration with HTTP middleware\n\nFirst add either the `GraphQL.Server.All` nuget package or the `GraphQL.Server.Transports.AspNetCore`\nnuget package to your application.  Referencing the \"all\" package will include the UI middleware\npackages.  These packages depend on `GraphQL` version 8.2.1 or later.\n\nThen update your `Program.cs` or `Startup.cs` to configure GraphQL, registering the schema\nand the serialization engine as a minimum.  Configure WebSockets and GraphQL in the HTTP\npipeline by calling `UseWebSockets` and `UseGraphQL` at the appropriate point.\nFinally, you may also include some UI middleware for easy testing of your GraphQL endpoint\nby calling `UseGraphQLGraphiQL` or a similar method at the appropriate point.\n\nBelow is a complete sample of a .NET 6 console app that hosts a GraphQL endpoint at\n`http://localhost:5000/graphql`:\n\n#### Project file\n\n```xml\n\u003cProject Sdk=\"Microsoft.NET.Sdk.Web\"\u003e\n\n  \u003cPropertyGroup\u003e\n    \u003cTargetFramework\u003enet6.0\u003c/TargetFramework\u003e\n    \u003cImplicitUsings\u003eenable\u003c/ImplicitUsings\u003e\n    \u003cNullable\u003eenable\u003c/Nullable\u003e\n  \u003c/PropertyGroup\u003e\n\n  \u003cItemGroup\u003e\n    \u003cPackageReference Include=\"GraphQL.Server.All\" Version=\"7.0.0\" /\u003e\n  \u003c/ItemGroup\u003e\n\n\u003c/Project\u003e\n```\n\n#### Program.cs file\n\n```csharp\nusing GraphQL;\n\nvar builder = WebApplication.CreateBuilder(args);\nbuilder.Services.AddGraphQL(b =\u003e b\n    .AddAutoSchema\u003cQuery\u003e()  // schema\n    .AddSystemTextJson());   // serializer\n\nvar app = builder.Build();\napp.UseDeveloperExceptionPage();\napp.UseWebSockets();\napp.UseGraphQL(\"/graphql\");            // url to host GraphQL endpoint\napp.UseGraphQLGraphiQL(\n    \"/\",                               // url to host GraphiQL at\n    new GraphQL.Server.Ui.GraphiQL.GraphiQLOptions\n    {\n        GraphQLEndPoint = \"/graphql\",         // url of GraphQL endpoint\n        SubscriptionsEndPoint = \"/graphql\",   // url of GraphQL endpoint\n    });\nawait app.RunAsync();\n```\n\n#### Schema\n\n```csharp\npublic class Query\n{\n    public static string Hero() =\u003e \"Luke Skywalker\";\n}\n```\n\n#### Sample request url\n\n```\nhttp://localhost:5000/graphql?query={hero}\n```\n\n#### Sample response\n\n```json\n{\"data\":{\"hero\":\"Luke Skywalker\"}}\n```\n\n### Basic options\n\nBy default, the middleware will be installed with these configurable options:\n- GET, POST, and WebSocket requests are all enabled\n- Form content types are disabled, and cross-site request forgery (CSRF)\n  protection is enabled\n- There are no authentication or authorization requirements\n- The default response content type is `application/graphql-response+json`\n- The middleware will use the default schema instance\n\nTo configure these options, pass a confiuguration delegate to the `UseGraphQL`\nmethod as demonstrated below:\n\n```csharp\napp.UseGraphQL(\"/graphql\", opts =\u003e {\n    opts.ReadFormOnPost = true;\n});\n```\n\nConfiguration of these options and more are further described below in this document.\n\n### Configuration with endpoint routing\n\nTo use endpoint routing, call `MapGraphQL` from inside the endpoint configuration\nbuilder rather than `UseGraphQL` on the application builder.  See below for the\nsample of the application builder code:\n\n```csharp\nvar app = builder.Build();\napp.UseDeveloperExceptionPage();\napp.UseWebSockets();\napp.UseRouting();\napp.UseEndpoints(endpoints =\u003e\n{\n    endpoints.MapGraphQL(\"graphql\");\n    endpoints.MapGraphQLVoyager(\"ui/voyager\");\n});\nawait app.RunAsync();\n```\n\nUsing endpoint routing is particularly useful when you want to select a specific\nCORS configuration for the GraphQL endpoint.  See the CORS section below for a sample.\n\nPlease note that when using endpoint routing, you cannot use WebSocket connections\nwhile a UI package is also configured at the same URL.  You will need to use a\ndifferent URL for the UI package, or use UI middleware prior to endpoint routing.\nSo long as different URLs are used, there are no issues.  Below is a sample when\nthe UI and GraphQL reside at the same URL:\n\n```csharp\nvar app = builder.Build();\napp.UseDeveloperExceptionPage();\napp.UseWebSockets();\napp.UseRouting();\napp.UseGraphQLVoyager(\"/graphql\");\napp.UseEndpoints(endpoints =\u003e\n{\n    endpoints.MapGraphQL(\"/graphql\");\n});\nawait app.RunAsync();\n```\n\n### Configuration with a MVC controller\n\nAlthough not recommended, you may set up a controller action to execute GraphQL\nrequests.  You will not need `UseGraphQL` or `MapGraphQL` in the application\nstartup.  You may use `GraphQLExecutionActionResult` to let the middleware\nhandle the entire parsing and execution of the request, including subscription\nrequests over WebSocket connections, or you can execute the request yourself,\nonly using `ExecutionResultActionResult` to serialize the result.\n\nYou can also reference the UI projects to display a GraphQL user interface as shown below.\n\n#### Using `GraphQLExecutionActionResult`\n\n```csharp\npublic class HomeController : Controller\n{\n    public IActionResult Index()\n        =\u003e new GraphiQLActionResult(opts =\u003e\n        {\n            opts.GraphQLEndPoint = \"/Home/graphql\";\n            opts.SubscriptionsEndPoint = \"/Home/graphql\";\n        });\n\n    [HttpGet]\n    [HttpPost]\n    [ActionName(\"graphql\")]\n    public IActionResult GraphQL()\n        =\u003e new GraphQLExecutionActionResult();\n}\n```\n\n#### Using `ExecutionResultActionResult`\n\nNote: this is very simplified; a much more complete sample can be found\nin the `Samples.Controller` project within this repository.\n\n```csharp\npublic class HomeController : Controller\n{\n    private readonly IDocumentExecuter _documentExecuter;\n\n    public TestController(IDocumentExecuter\u003cISchema\u003e documentExecuter)\n    {\n        _documentExecuter = documentExecuter;\n    }\n\n    [HttpGet]\n    public async Task\u003cIActionResult\u003e GraphQL(string query)\n    {\n        var result = await _documentExecuter.ExecuteAsync(new()\n        {\n            Query = query,\n            RequestServices = HttpContext.RequestServices,\n            CancellationToken = HttpContext.RequestAborted,\n        });\n        return new ExecutionResultActionResult(result);\n    }\n}\n```\n\n### Configuration with Azure Functions\n\nThis project also supports hosting GraphQL endpoints within Azure Functions.\nYou will need to complete the following steps:\n\n1. Configure the Azure Function to use Dependency Injection:\n   See https://learn.microsoft.com/en-us/azure/azure-functions/functions-dotnet-dependency-injection\n   for details.\n\n2. Configure GraphQL via `builder.Services.AddGraphQL()` the same as you would in a typical\n   ASP.NET Core application.\n\n3. Add an HTTP function that returns an appropriate `ActionResult`:\n\n```csharp\n[FunctionName(\"GraphQL\")]\npublic static IActionResult RunGraphQL(\n    [HttpTrigger(AuthorizationLevel.Anonymous, \"get\", \"post\"] HttpRequest req)\n{\n    return new GraphQLExecutionActionResult();\n}\n```\n\n4. Optionally, add a UI package to the project and configure it:\n\n```csharp\n[FunctionName(\"GraphiQL\")]\npublic static IActionResult RunGraphiQL(\n    [HttpTrigger(AuthorizationLevel.Anonymous, \"get\"] HttpRequest req)\n{\n    return new GraphiQLActionResult(opts =\u003e opts.GraphQLEndPoint = \"/api/graphql\");\n}\n```\n\nMiddleware can be configured by passing a configuration delegate to `new GraphQLExecutionActionResult()`.\nMultiple schemas are supported by the use of `GraphQLExecutionActionResult\u003cTSchema\u003e()`.\nIt is not possible to configure subscription support, as Azure Functions do not support WebSockets\nsince it is a serverless environment.\n\nSee the `Samples.AzureFunctions` project for a complete sample based on the\n.NET template for Azure Functions.\n\nPlease note that the GraphQL schema needs to be initialized for every call through\nAzure Functions, since it is a serverless environment.  This is done automatically\nbut will come at a performance cost.  If you are using a schema that is expensive\nto initialize, you may want to consider using a different hosting environment.\n\n### User context configuration\n\nTo set the user context to be used during the execution of GraphQL requests,\ncall `AddUserContextBuilder` during the GraphQL service setup to set a delegate\nwhich will be called when the user context is built.  Alternatively, you can\nregister an `IUserContextBuilder` implementation to do the same.\n\n#### Program.cs / Startup.cs\n\n```csharp\nbuilder.Services.AddGraphQL(b =\u003e b\n    .AddAutoSchema\u003cQuery\u003e()\n    .AddSystemTextJson()\n    .AddUserContextBuilder(httpContext =\u003e new MyUserContext(httpContext));\n```\n\n#### MyUserContext.cs\n\n```csharp\npublic class MyUserContext : Dictionary\u003cstring, object?\u003e\n{\n    public ClaimsPrincipal User { get; }\n\n    public MyUserContext(HttpContext context)\n    {\n        User = context.User;\n    }\n}\n```\n\n### Authorization configuration\n\nYou can configure authorization for all GraphQL requests, or for individual\ngraphs, fields and query arguments within your schema.  Both can be used\nif desired.\n\nBe sure to call `app.UseAuthentication()` and `app.UseAuthorization()` prior\nto the call to `app.UseGraphQL()`.  For example:\n\n```csharp\napp.UseAuthentication();\napp.UseAuthorization();\napp.UseWebSockets();\napp.UseGraphQL(\"/graphql\");\n```\n\n#### Endpoint authorization (which would include introspection requests)\n\nEndpoint authorization will check authorization requirements are met for the entire\nGraphQL endpoint, including introspection requests.  These checks occur prior to parsing,\nvalidating or executing the document.\n\nWhen calling `UseGraphQL`, specify options as necessary to configure authorization as required.\n\n```csharp\napp.UseGraphQL(\"/graphql\", config =\u003e\n{\n    // require that the user be authenticated\n    config.AuthorizationRequired = true;\n\n    // require that the user be a member of at least one role listed\n    config.AuthorizedRoles.Add(\"MyRole\");\n    config.AuthorizedRoles.Add(\"MyAlternateRole\");\n\n    // require that the user pass a specific authorization policy\n    config.AuthorizedPolicy = \"MyPolicy\";\n});\n```\n\n#### For individual graph types, fields and query arguments\n\nTo configure the ASP.NET Core authorization validation rule for GraphQL, add the corresponding\nvalidation rule during GraphQL configuration, typically by calling `.AddAuthorizationRule()`\nas shown below:\n\n```csharp\nbuilder.Services.AddGraphQL(b =\u003e b\n    .AddAutoSchema\u003cQuery\u003e()\n    .AddSystemTextJson()\n    .AddAuthorizationRule());\n```\n\nBoth roles and policies are supported for output graph types, fields on output graph types,\nand query arguments.  If multiple policies are specified, all must match; if multiple roles\nare specified, any one role must match.  You may also use `.Authorize()` and/or the\n`[Authorize]` attribute to validate that the user has authenticated.  You may also use\n`.AllowAnonymous()` and/or `[AllowAnonymous]` to allow fields to be returned to\nunauthenticated users within an graph that has an authorization requirement defined.\n\nPlease note that authorization rules do not apply to values returned within introspection requests,\npotentially leaking information about protected areas of the schema to unauthenticated users.\nYou may use the `ISchemaFilter` to restrict what information is returned from introspection\nrequests, but it will apply to both authenticated and unauthenticated users alike.\n\nIntrospection requests are allowed unless the schema has an authorization requirement set on it.\nThe `@skip` and `@include` directives are honored, skipping authorization checks for fields\nor fragments skipped by `@skip` or `@include`.\n\nPlease note that if you use interfaces, validation might be executed against the graph field\nor the interface field, depending on the structure of the query.  For instance:\n\n```graphql\n{\n  cat {\n    # validates against Cat.Name\n    name\n\n    # validates against Animal.Name\n    ... on Animal {\n      name\n    }\n  }\n}\n```\n\nSimilarly for unions, validation occurs on the exact type that is queried.  Be sure to carefully\nconsider placement of authorization rules when using interfaces and unions, especially when some\nfields are marked with `AllowAnonymous`.\n\n| :warning: Note that authorization rules are ignored for input types and fields of input types :warning: |\n|-|\n\n#### Custom authentication configuration for GET/POST requests\n\nTo provide custom authentication code, bypassing ASP.NET Core's authentication, derive from the\n`GraphQLHttpMiddleware\u003cT\u003e` class and override `HandleAuthorizeAsync`, setting `HttpContext.User`\nto an appropriate `ClaimsPrincipal` instance.\n\nSee 'Customizing middleware behavior' below for an example of deriving from `GraphQLHttpMiddleware`.\n\n#### Authentication for WebSocket requests\n\nSince WebSocket requests from browsers cannot typically carry a HTTP Authorization header, you\nwill need to authorize requests via the `ConnectionInit` WebSocket message or carry the authorization\ntoken within the URL.  Below is a sample of the former:\n\n```cs\nbuilder.Services.AddGraphQL(b =\u003e b\n    .AddAutoSchema\u003cQuery\u003e()\n    .AddSystemTextJson()\n    .AddAuthorizationRule()  // not required for endpoint authorization\n    .AddWebSocketAuthentication\u003cMyAuthService\u003e());\n\napp.UseGraphQL(\"/graphql\", config =\u003e\n{\n    // require that the user be authenticated\n    config.AuthorizationRequired = true;\n});\n\nclass MyAuthService : IWebSocketAuthenticationService\n{\n    private readonly IGraphQLSerializer _serializer;\n\n    public MyAuthService(IGraphQLSerializer serializer)\n    {\n        _serializer = serializer;\n    }\n\n    public async ValueTask\u003cbool\u003e AuthenticateAsync(IWebSocketConnection connection, OperationMessage operationMessage)\n    {\n        // read payload of ConnectionInit message and look for an \"Authorization\" entry that starts with \"Bearer \"\n        var payload = _serializer.ReadNode\u003cInputs\u003e(operationMessage.Payload);\n        if ((payload?.TryGetValue(\"Authorization\", out var value) ?? false) \u0026\u0026 value is string valueString)\n        {\n            var user = ParseToken(valueString);\n            if (user != null)\n            {\n                // set user and indicate authentication was successful\n                connection.HttpContext.User = user;\n                return true;\n            }\n        }\n        return false; // authentication failed\n    }\n\n    private ClaimsPrincipal? ParseToken(string authorizationHeaderValue)\n    {\n        // parse header value and return user, or null if unable\n    }\n}\n```\n\nTo authorize based on information within the query string, it is recommended to\nderive from `GraphQLHttpMiddleware\u003cT\u003e` and override `InvokeAsync`, setting\n`HttpContext.User` based on the query string parameters, and then calling `base.InvokeAsync`.\nAlternatively you may override `HandleAuthorizeAsync` which will execute for GET/POST requests,\nand `HandleAuthorizeWebSocketConnectionAsync` for WebSocket requests.\nNote that `InvokeAsync` will execute even if the protocol is disabled in the options via\ndisabling `HandleGet` or similar; `HandleAuthorizeAsync` and `HandleAuthorizeWebSocketConnectionAsync`\nwill not.\n\n#### Authentication schemes\n\nBy default the role and policy requirements are validated against the current user as defined by\n`HttpContext.User`.  This is typically set by ASP.NET Core's authentication middleware and is based\non the default authentication scheme set during the call to `AddAuthentication` in `Startup.cs`.\nYou may override this behavior by specifying a different authentication scheme via the `AuthenticationSchemes`\noption.  For instance, if you wish to authenticate using JWT authentication when Cookie authentication is\nthe default, you may specify the scheme as follows:\n\n```csharp\napp.UseGraphQL(\"/graphql\", config =\u003e\n{\n    // specify a specific authentication scheme to use\n    config.AuthenticationSchemes.Add(JwtBearerDefaults.AuthenticationScheme);\n});\n```\n\nThis will overwrite the `HttpContext.User` property when handling GraphQL requests, which will in turn\nset the `IResolveFieldContext.User` property to the same value (unless being overridden via an\n`IWebSocketAuthenticationService` implementation as shown above).  So both endpoint authorization and\nfield authorization will perform role and policy checks against the same authentication scheme.\n\n### UI configuration\n\nThere are four UI middleware projects included; Altair, GraphiQL, Playground and Voyager.\nPlayground has not been updated since 2019 and is deprecated in favor of GraphiQL.\nSee review the following methods for configuration options within each of the 4 respective\nNuGet packages:\n\n```csharp\napp.UseGraphQLAltair();\napp.UseGraphQLGraphiQL();\napp.UseGraphQLPlayground();  // deprecated\napp.UseGraphQLVoyager();\n\n// or\n\nendpoints.MapGraphQLAltair();\nendpoints.MapGraphQLGraphiQL();\nendpoints.MapGraphQLPlayground();  // deprecated\nendpoints.MapGraphQLVoyager();\n```\n\n### CORS configuration\n\nASP.NET Core supports CORS requests independently of GraphQL, including CORS pre-flight\nrequests.  To configure your application for CORS requests, add `AddCors()` and `UseCors()`\ninto the application pipeline.\n\n```csharp\nbuilder.Services.AddCors();\n\napp.UseCors(policy =\u003e {\n    // configure default policy here\n});\n```\n\nTo configure GraphQL to use a named CORS policy, configure the application to use endpoint routing\nand call `RequireCors()` on the endpoint configuration builder.\n\n```csharp\n// ...\nbuilder.Services.AddRouting();\nbuilder.Services.AddCors(builder =\u003e\n{\n    // configure named and/or default policies here\n});\n\nvar app = builder.Build();\napp.UseDeveloperExceptionPage();\napp.UseWebSockets();\napp.UseRouting();\napp.UseCors();\napp.UseEndpoints(endpoints =\u003e\n{\n    // configure the graphql endpoint with the specified CORS policy\n    endpoints.MapGraphQL()\n        .RequireCors(\"MyCorsPolicy\");\n});\nawait app.RunAsync();\n```\n\nIn order to ensure that all requests trigger CORS preflight requests, by default the server\nwill reject requests that do not meet one of the following criteria:\n\n- The request is a POST request that includes a Content-Type header that is not\n  `application/x-www-form-urlencoded`, `multipart/form-data`, or `text/plain`.\n- The request includes a non-empty `GraphQL-Require-Preflight` header.\n\nTo disable this behavior, set the `CsrfProtectionEnabled` option to `false`.\n\n```csharp\napp.UseGraphQL(\"/graphql\", config =\u003e\n{\n    config.CsrfProtectionEnabled = false;\n});\n```\n\nYou may also change the allowed headers by modifying the `CsrfProtectionHeaders` option.\n\n```csharp\napp.UseGraphQL(\"/graphql\", config =\u003e\n{\n    config.CsrfProtectionHeaders = [\"MyCustomHeader\"];\n});\n```\n\n### Response compression\n\nASP.NET Core supports response compression independently of GraphQL, with brotli and gzip\nsupport automatically based on the compression formats listed as supported in the request headers.\nTo configure your application for response compression, configure your Program/Startup file as\nfollows:\n\n```csharp\n// add and configure the service\nbuilder.Services.AddResponseCompression(options =\u003e\n{\n    options.EnableForHttps = true; // may lead to CRIME and BREACH attacks\n    options.MimeTypes = new[] { \"application/json\", \"application/graphql-response+json\" };\n})\n\n// place this first/early in the pipeline\napp.UseResponseCompression();\n```\n\nIn order to compress GraphQL responses, the `application/graphql-response+json` content type must be\nadded to the `MimeTypes` option.  You may choose to enable other content types as well.\n\nPlease note that enabling response compression over HTTPS can lead to CRIME and BREACH\nattacks.  These side-channel attacks typically affects sites that rely on cookies for\nauthentication.  Please read [this](https://docs.microsoft.com/en-us/aspnet/core/performance/response-compression?view=aspnetcore-6.0)\nand [this](http://www.breachattack.com/#howitworks) for more details.\n\n### ASP.NET Core 2.1 / .NET Framework 4.8\n\nYou may choose to use the .NET Core 2.1 runtime or the .NET Framework 4.8 runtime.\nThis library has been tested with .NET Core 2.1 and .NET Framework 4.8.\n\nThe only additional requirement is that you must add this code in your `Startup.cs` file:\n\n```csharp\nservices.AddHostApplicationLifetime();\n```\n\nBesides that requirement, all features are supported in exactly the same manner as\nwhen using ASP.NET Core 3.1+.  You may find differences in the ASP.NET Core runtime,\nsuch as CORS implementation differences, which are outside the scope of this project.\n\nPlease note that a serializer reference is not included for these projects within\n`GraphQL.Server.Transports.AspNetCore`; you will need to reference either\n`GraphQL.NewtonsoftJson` or `GraphQL.SystemTextJson`, or reference\n`GraphQL.Server.All` which includes `GraphQL.NewtonsoftJson` for ASP.NET Core 2.1 projects.\nThis is because `Newtonsoft.Json` is the default serializer for ASP.NET Core 2.1\nrather `System.Text.Json`.  When using `GraphQL.NewtonsoftJson`, you will need to call\n`AddNewtonsoftJson()` rather than `AddSystemTextJson()` while configuring GraphQL.NET.\n\n\u003cdetails\u003e\u003csummary\u003eMicrosoft support policy\u003c/summary\u003e\u003cp\u003e\n\nPlease note that .NET Core 2.1 is currently out of support by Microsoft.\n.NET Framework 4.8 is supported, and ASP.NET Core 2.1 is supported when run on\n.NET Framework 4.8.  Please see these links for more information:\n\n- https://dotnet.microsoft.com/en-us/platform/support/policy/dotnet-framework\n- https://dotnet.microsoft.com/en-us/platform/support/policy/aspnetcore-2.1\n\n\u003c/p\u003e\u003c/details\u003e\n\n## Advanced configuration\n\nFor more advanced configurations, see the overloads and configuration options\navailable for the various builder methods, listed below.  Methods and properties\ncontain XML comments to provide assistance while coding with your IDE.\n\n| Builder interface       | Method                  | Description |\n|-------------------------|-------------------------|-------------|\n| `IGraphQLBuilder`       | `AddUserContextBuilder` | Sets up a delegate to create the UserContext for each GraphQL request. |\n| `IApplicationBuilder`   | `UseGraphQL`            | Adds the GraphQL middleware to the HTTP request pipeline. |\n| `IEndpointRouteBuilder` | `MapGraphQL`            | Adds the GraphQL middleware to the HTTP request pipeline. |\n\nA number of the methods contain optional parameters or configuration delegates to\nallow further customization.  Please review the overloads of each method to determine\nwhich options are available.  In addition, many methods have more descriptive XML\ncomments than shown above.\n\n### Configuration options\n\nBelow are descriptions of the options available when registering the HTTP middleware.\nNote that the HTTP middleware options are configured via the `UseGraphQL` or `MapGraphQL`\nmethods allowing for different options for each configured endpoint.\n\n#### GraphQLHttpMiddlewareOptions\n\n| Property                           | Description     | Default value |\n|------------------------------------|-----------------|---------------|\n| `AuthorizationRequired`            | Requires `HttpContext.User` to represent an authenticated user. | False |\n| `AuthorizedPolicy`                 | If set, requires `HttpContext.User` to pass authorization of the specified policy. | |\n| `AuthorizedRoles`                  | If set, requires `HttpContext.User` to be a member of any one of a list of roles. | |\n| `CsrfProtectionEnabled`            | Enables cross-site request forgery (CSRF) protection for both GET and POST requests. | True |\n| `CsrfProtectionHeaders`            | Sets the headers used for CSRF protection when necessary. | `GraphQL-Require-Preflight` |\n| `DefaultResponseContentType`       | Sets the default response content type used within responses. | `application/graphql-response+json; charset=utf-8` |\n| `EnableBatchedRequests`            | Enables handling of batched GraphQL requests for POST requests when formatted as JSON. | True |\n| `ExecuteBatchedRequestsInParallel` | Enables parallel execution of batched GraphQL requests. | True |\n| `HandleGet`                        | Enables handling of GET requests. | True |\n| `HandlePost`                       | Enables handling of POST requests. | True |\n| `HandleWebSockets`                 | Enables handling of WebSockets requests. | True |\n| `MaximumFileSize`                  | Sets the maximum file size allowed for GraphQL multipart requests. | unlimited |\n| `MaximumFileCount`                 | Sets the maximum number of files allowed for GraphQL multipart requests. | unlimited |\n| `ReadExtensionsFromQueryString`    | Enables reading extensions from the query string. | True |\n| `ReadFormOnPost`                   | Enables parsing of form data for POST requests (may have security implications). | False |\n| `ReadQueryStringOnPost`            | Enables parsing the query string on POST requests. | True |\n| `ReadVariablesFromQueryString`     | Enables reading variables from the query string. | True |\n| `ValidationErrorsReturnBadRequest` | When enabled, GraphQL requests with validation errors have the HTTP status code set to 400 Bad Request. | Automatic[^1] |\n| `WebSockets`                       | Returns a set of configuration properties for WebSocket connections. | |\n\n[^1]: Automatic mode will return a 200 OK status code when the returned content type is `application/json`; otherwise 400 or as defined by the error.\n\n#### GraphQLWebSocketOptions\n\n| Property                    | Description          | Default value |\n|-----------------------------|----------------------|---------------|\n| `ConnectionInitWaitTimeout` | The amount of time to wait for a GraphQL initialization packet before the connection is closed. | 10 seconds |\n| `DisconnectionTimeout`      | The amount of time to wait to attempt a graceful teardown of the WebSockets protocol. | 10 seconds |\n| `DisconnectAfterErrorEvent` | Disconnects a subscription from the client if the subscription source dispatches an `OnError` event. | True |\n| `DisconnectAfterAnyError`   | Disconnects a subscription from the client if there are any GraphQL errors during a subscription. | False |\n| `KeepAliveMode`             | The mode to use for sending keep-alive packets. | protocol-dependent |\n| `KeepAliveTimeout`          | The amount of time to wait between sending keep-alive packets. | disabled |\n| `SupportedWebSocketSubProtocols` | A list of supported WebSocket sub-protocols. | `graphql-ws`, `graphql-transport-ws` |\n\n### Multi-schema configuration\n\nYou may use the generic versions of the various builder methods to map a URL to a particular schema.\n\n```csharp\nvar app = builder.Build();\napp.UseDeveloperExceptionPage();\napp.UseGraphQL\u003cDogSchema\u003e(\"/dogs/graphql\");\napp.UseGraphQL\u003cCatSchema\u003e(\"/cats/graphql\");\nawait app.RunAsync();\n```\n\n### Different global authorization settings for different transports (GET/POST/WebSockets)\n\nYou may register the same endpoint multiple times if necessary to configure GET connections\nwith certain authorization options, and POST connections with other authorization options.\n\n```csharp\nvar app = builder.Build();\napp.UseDeveloperExceptionPage();\napp.UseGraphQL(\"/graphql\", options =\u003e\n{\n    options.HandleGet = true;\n    options.HandlePost = false;\n    options.HandleWebSockets = false;\n    options.AuthorizationRequired = false;\n});\napp.UseGraphQL(\"/graphql\", options =\u003e\n{\n    options.HandleGet = false;\n    options.HandlePost = true;\n    options.HandleWebSockets = true;\n    options.AuthorizationRequired = true;   // require authentication for POST/WebSocket connections\n});\nawait app.RunAsync();\n```\n\nSince POST and WebSockets can be used for query requests, it is recommended not to do the above,\nbut instead add the authorization validation rule and add authorization metadata on the Mutation\nand Subscription portions of your schema, as shown below:\n\n```csharp\nbuilder.Services.AddGraphQL(b =\u003e b\n    .AddSchema\u003cMySchema\u003e()\n    .AddSystemTextJson()\n    .AddAuthorizationRule()); // add authorization validation rule\n\nvar app = builder.Build();\napp.UseDeveloperExceptionPage();\napp.UseGraphQL();\nawait app.RunAsync();\n\n// demonstration of code-first schema; also possible with schema-first or type-first schemas\npublic class MySchema : Schema\n{\n    public MySchema(IServiceProvider provider, MyQuery query, MyMutation mutation) : base(provider)\n    {\n        Query = query;\n        Mutation = mutation;\n\n        mutation.Authorize(); // require authorization for any mutation request\n    }\n}\n```\n\n### Keep-alive configuration\n\nBy default, the middleware will not send keep-alive packets to the client.  As the underlying\noperating system may not detect a disconnected client until a message is sent, you may wish to\nenable keep-alive packets to be sent periodically.  The default mode for keep-alive packets\ndiffers depending on whether the client connected with the `graphql-ws` or `graphql-transport-ws`\nsub-protocol.  The `graphql-ws` sub-protocol will send a unidirectional keep-alive packet to the\nclient on a fixed schedule, while the `graphql-transport-ws` sub-protocol will only send\nunidirectional keep-alive packets when the client has not sent a message within a certain time.\nThe differing behavior is due to the default implementation of the `graphql-ws` sub-protocol\nclient, which after receiving a single keep-alive packet, expects additional keep-alive packets\nto be sent sooner than every 20 seconds, regardless of the client's activity.\n\nTo configure keep-alive packets, set the `KeepAliveMode` and `KeepAliveTimeout` properties\nwithin the `GraphQLWebSocketOptions` object.  Set the `KeepAliveTimeout` property to\nenable keep-alive packets, or use `TimeSpan.Zero` or `Timeout.InfiniteTimeSpan` to disable it.\n\nThe `KeepAliveMode` property is only applicable to the `graphql-transport-ws` sub-protocol and\ncan be set to the options listed below:\n\n| Keep-alive mode | Description |\n|-----------------|-------------|\n| `Default`       | Same as `Timeout`. |\n| `Timeout`       | Sends a unidirectional keep-alive message when no message has been received within the specified timeout period. |\n| `Interval`      | Sends a unidirectional keep-alive message at a fixed interval, regardless of message activity. |\n| `TimeoutWithPayload` | Sends a bidirectional keep-alive message with a payload on a fixed interval, and validates the payload matches in the response. |\n\nThe `TimeoutWithPayload` model is particularly useful when the server may send messages to the\nclient at a faster pace than the client can process them.  In this case queued messages will be\nlimited to double the timeout period, as the keep-alive message is queued along with other\npackets sent from the server to the client.  The client will need to respond to process queued\nmessages and respond to the keep-alive message within the timeout period or the server will\ndisconnect the client.  When the server forcibly disconnects the client, no graceful teardown\nof the WebSocket protocol occurs, and any queued messages are discarded.\n\nWhen using the `TimeoutWithPayload` keep-alive mode, you may wish to enforce that the\n`graphql-transport-ws` sub-protocol is in use by the client, as the `graphql-ws` sub-protocol\ndoes not support bidirectional keep-alive packets.  This can be done by setting the\n`SupportedWebSocketSubProtocols` property to only include the `graphql-transport-ws` sub-protocol.\n\n```csharp\napp.UseGraphQL(\"/graphql\", options =\u003e\n{\n    // configure keep-alive packets\n    options.WebSockets.KeepAliveTimeout = TimeSpan.FromSeconds(10);\n    options.WebSockets.KeepAliveMode = KeepAliveMode.TimeoutWithPayload;\n    // set the supported sub-protocols to only include the graphql-transport-ws sub-protocol\n    options.WebSockets.SupportedWebSocketSubProtocols = [GraphQLWs.SubscriptionServer.SubProtocol];\n});\n```\n\nPlease note that the included UI packages are configured to use the `graphql-ws` sub-protocol by\ndefault.  You may use the `graphql-transport-ws` sub-protocol with the GraphiQL package by setting\nthe `GraphQLWsSubscriptions` option to `true` when configuring the GraphiQL middleware.\n\n### Customizing middleware behavior\n\nGET/POST requests are handled directly by the `GraphQLHttpMiddleware`.\nFor WebSocket requests an `WebSocketConnection` instance is created to dispatch incoming\nmessages and send outgoing messages.  Depending on the WebSocket sub-protocols supported by the\nclient, the proper implementation of `IOperationMessageProcessor` is created to act as a\nstate machine, processing incoming messages and sending outgoing messages through the\n`WebSocketConnection` instance.\n\n#### GraphQLHttpMiddleware\n\nThe base middleware functionality is contained within `GraphQLHttpMiddleware`, with code\nto perform execution of GraphQL requests in the derived class `GraphQLHttpMiddleware\u003cTSchema\u003e`.\nThe classes are organized as follows:\n\n- `InvokeAsync` is the entry point to the middleware.  For WebSocket connection requests,\n  execution is immediately passed to `HandleWebSocketAsync`.\n- Methods that start with `Handle` are passed the `HttpContext` and `RequestDelegate`\n  instance, and may handle the request or pass execution to the `RequestDelegate` thereby\n  skipping this execution handler.  This includes methods to handle execution of single or\n  batch queries or returning error conditions.\n- Methods that start with `Write` are for writing responses to the output stream.\n- Methods that start with `Execute` are for executing GraphQL requests.\n\nA list of methods are as follows:\n\n| Method                      | Description |\n|-----------------------------|-------------|\n| `InvokeAsync`               | Entry point of the middleware |\n| `HandleRequestAsync`        | Handles a single GraphQL request. |\n| `HandleBatchRequestAsync`   | Handles a batched GraphQL request. |\n| `HandleWebSocketAsync`      | Handles a WebSocket connection request. |\n| `BuildUserContextAsync`     | Builds the user context based on a `HttpContext`. |\n| `ExecuteRequestAsync`       | Executes a GraphQL request. |\n| `ExecuteScopedRequestAsync` | Executes a GraphQL request with a scoped service provider. |\n| `SelectResponseContentType` | Selects a content-type header for the JSON-formatted GraphQL response. |\n| `WriteErrorResponseAsync`   | Writes the specified error message as a JSON-formatted GraphQL response, with the specified HTTP status code. |\n| `WriteJsonResponseAsync`    | Writes the specified object (usually a GraphQL response) as JSON to the HTTP response stream. |\n\n| Error handling method                         | Description |\n|-----------------------------------------------|-------------|\n| `HandleBatchedRequestsNotSupportedAsync`      | Writes a '400 Batched requests are not supported.' message to the output. |\n| `HandleContentTypeCouldNotBeParsedErrorAsync` | Writes a '415 Invalid Content-Type header: could not be parsed.' message to the output. |\n| `HandleDeserializationErrorAsync`             | Writes a '400 JSON body text could not be parsed.' message to the output. |\n| `HandleInvalidContentTypeErrorAsync`          | Writes a '415 Invalid Content-Type header: non-supported type.' message to the output. |\n| `HandleInvalidHttpMethodErrorAsync`           | Indicates that an unsupported HTTP method was requested. Executes the next delegate in the chain by default. |\n| `HandleWebSocketSubProtocolNotSupportedAsync` | Writes a '400 Invalid WebSocket sub-protocol.' message to the output. |\n\nBelow is a sample of custom middleware to change the response content type to `application/json`,\nregardless of the value of the HTTP 'Accept' header or default value set in the options:\n\n```csharp\nclass MyMiddleware\u003cTSchema\u003e : GraphQLHttpMiddleware\u003cTSchema\u003e\n    where TSchema : ISchema\n{\n    public MyMiddleware(\n        RequestDelegate next,\n        IGraphQLTextSerializer serializer,\n        IDocumentExecuter\u003cTSchema\u003e documentExecuter,\n        IServiceScopeFactory serviceScopeFactory,\n        GraphQLHttpMiddlewareOptions options,\n        IHostApplicationLifetime hostApplicationLifetime)\n        : base(next, serializer, documentExecuter, serviceScopeFactory, options, hostApplicationLifetime)\n    {\n    }\n\n    protected override string SelectResponseContentType(HttpContext context)\n        =\u003e \"application/json\";\n}\n\napp.UseGraphQL\u003cMyMiddleware\u003cISchema\u003e\u003e(\"/graphql\", new GraphQLHttpMiddlewareOptions());\n```\n\nBe sure to derive from `GraphQLHttpMiddleware\u003cTSchema\u003e` rather than `GraphQLHttpMiddleware`\nas shown above for multi-schema compatibility.\n\n#### WebSocket handler classes\n\nThe WebSocket handling code is organized as follows:\n\n| Interface / Class                | Description |\n|----------------------------------|-------------|\n| `IWebSocketConnection`           | Provides methods to send a message to a client or close the connection. |\n| `IOperationMessageProcessor`     | Handles incoming messages from the client. |\n| `GraphQLWebSocketOptions`        | Provides configuration options for WebSocket connections. |\n| `WebSocketConnection`            | Standard implementation of a message pump for `OperationMessage` messages across a WebSockets connection.  Implements `IWebSocketConnection` and delivers messages to a specified `IOperationMessageProcessor`. |\n| `BaseSubscriptionServer`         | Abstract implementation of `IOperationMessageProcessor`, a message handler for `OperationMessage` messages.  Provides base functionality for managing subscriptions and requests. |\n| `GraphQLWs.SubscriptionServer`   | Implementation of `IOperationMessageProcessor` for the `graphql-transport-ws` sub-protocol. |\n| `SubscriptionsTransportWs.SubscriptionServer` | Implementation of `IOperationMessageProcessor` for the `graphql-ws` sub-protocol. |\n| `IWebSocketAuthorizationService` | Allows authorization of GraphQL requests for WebSocket connections. |\n\nTypically if you wish to change functionality or support another sub-protocol\nyou will need to perform the following:\n\n1. Derive from either `SubscriptionServer` class, modifying functionality as needed, or to support\n   a new protocol, derive from `BaseSubscriptionServer`.\n2. Derive from `GraphQLHttpMiddleware\u003cT\u003e` and override `CreateMessageProcessor` and/or\n   `SupportedWebSocketSubProtocols` as needed.\n3. Change the `app.AddGraphQL()` call to use your custom middleware, being sure to include an instance\n   of the options class that your middleware requires (typically `GraphQLHttpMiddlewareOptions`).\n\nThere exists a few additional classes to support the above.  Please refer to the source code\nof `GraphQLWs.SubscriptionServer` if you are attempting to add support for another protocol.\n\n## Additional notes / FAQ\n\n### Service scope\n\nBy default, a dependency injection service scope is created for each GraphQL execution\nin cases where it is possible that multiple GraphQL requests may be executing within the\nsame service scope:\n\n1. A batched GraphQL request is executed.\n2. A GraphQL request over a WebSocket connection is executed.\n\nHowever, field resolvers for child fields of subscription nodes will not by default execute\nwith a service scope.  Rather, the `context.RequestServices` property will contain a reference\nto a disposed service scope that cannot be used.\n\nTo solve this issue, please configure the scoped subscription execution strategy from the\nGraphQL.MicrosoftDI package as follows:\n\n```csharp\nservices.AddGraphQL(b =\u003e b\n    .AddAutoSchema\u003cQuery\u003e()\n    .AddSystemTextJson()\n    // configure queries for serial execution (optional)\n    .AddExecutionStrategy\u003cSerialExecutionStrategy\u003e(OperationType.Query)\n    // configure subscription field resolvers for scoped serial execution (parallel is optional)\n    .AddScopedSubscriptionExecutionStrategy());\n```\n\nFor single GET / POST requests, the service scope from the underlying HTTP context is used.\n\n### User context builder\n\nThe user context builder interface is executed only once, within the dependency injection\nservice scope of the original HTTP request.  For batched requests, the same user context\ninstance is passed to each GraphQL execution.  For WebSocket requests, the same user\ncontext instance is passed to each GraphQL subscription and data event resolver execution.\n\nAs such, do not create objects within the user context that rely on having the same\ndependency injection service scope as the field resolvers.  Since WebSocket connections\nare long-lived, using scoped services within a user context builder will result in those\nscoped services having a matching long lifetime.  You may wish to alleviate this by\ncreating a service scope temporarily within your user context builder.\n\nFor applications that service multiple schemas, you may register `IUserContextBuilder\u003cTSchema\u003e`\nto create a user context for a specific schema.  This is useful when you need to create\na user context that is specific to a particular schema.\n\n### Mutations within GET requests\n\nFor security reasons and pursuant to current recommendations, mutation GraphQL requests\nare rejected over HTTP GET connections.  Derive from `GraphQLHttpMiddleware\u003cT\u003e` and override\n`ExecuteRequestAsync` to prevent injection of the validation rules that enforce this behavior.\n\nAs would be expected, subscription requests are only allowed over WebSocket channels.\n\n### Handling form data for POST requests\n\nThe GraphQL over HTTP specification does not outline a procedure for transmitting GraphQL requests via\nHTTP POST connections using a `Content-Type` of `application/x-www-form-urlencoded` or `multipart/form-data`.\nAllowing the processing of such requests could be advantageous in avoiding CORS preflight requests when\nsending GraphQL queries from a web browser.  Nevertheless, enabling this feature may give rise to security\nrisks when utilizing cookie authentication, since transmitting cookies with these requests does not trigger\na pre-flight CORS check.  As a consequence, GraphQL.NET might execute a request and potentially modify data\neven when the CORS policy prohibits it, regardless of whether the sender has access to the response.\nThis situation exposes the system to security vulnerabilities, which should be carefully evaluated and\nmitigated to ensure the safe handling of GraphQL requests and maintain the integrity of the data.\n\nTo mitigate this potential security vulnerability, CSRF protection is enabled by default, requiring a\n`GraphQL-Require-Preflight` header to be sent with form data requests, which will trigger a CORS preflight\nrequest.  In addition, form data requests are disabled by default, as they are not recommended for typical\nuse.\n\nTo enable form data for POST request, set the `ReadFormOnPost` setting to `true`.  GraphQL.NET Server supports\ntwo formats of `application/x-www-form-urlencoded` or `multipart/form-data` requests:\n\n1. The following keys are read from the form data and used to populate the GraphQL request:\n   - `query`: The GraphQL query string.\n   - `operationName`: The name of the operation to execute.\n   - `variables`: A JSON-encoded object containing the variables for the operation.\n   - `extensions`: A JSON-encoded object containing the extensions for the operation.\n\n2. The following keys are read from the form data and used to populate the GraphQL request:\n   - `operations`: A JSON-encoded object containing the GraphQL request, in the same format as typical\n     requests sent via `application/json`.  This can be a single object or an array of objects if batching\n     is enabled.\n   - `map`: An optional JSON-encoded map of file keys to file objects.  This is used to map attached files\n     into the GraphQL request's variables property.  See the section below titled 'File uploading/downloading' and the\n     [GraphQL multipart request specification](https://github.com/jaydenseric/graphql-multipart-request-spec)\n     for additional details.  Since `application/x-www-form-urlencoded` cannot transmit files, this feature\n     is only available for `multipart/form-data` requests.\n\n### Excessive `OperationCanceledException`s\n\nWhen hosting a WebSockets endpoint, it may be common for clients to simply disconnect rather\nthan gracefully terminating the connection — most specifically when the client is a web browser.\nIf you log exceptions, you may notice an `OperationCanceledException` logged any time this occurs.\n\nIn some scenarios you may wish to log these exceptions — for instance, when the GraphQL endpoint is\nused in server-to-server communications — but if you wish to ignore these exceptions, simply call\n`app.UseIgnoreDisconnections();` immediately after any exception handling or logging configuration calls.\nThis will consume any `OperationCanceledException`s when `HttpContext.RequestAborted` is signaled — for\na WebSocket request or any other request.\n\n```csharp\nvar app = builder.Build();\napp.UseDeveloperExceptionPage();\napp.UseIgnoreDisconnections();\napp.UseWebSockets();\napp.UseGraphQL();\n```\n\n### File uploading/downloading\n\nA common question is how to upload or download files attached to GraphQL data.\nFor instance, storing and retrieving photographs attached to product data.\n\nOne common technique is to encode the data as Base64 and transmitting as a custom\nGraphQL scalar (encoded as a string value within the JSON transport).\nThis may not be ideal, but works well for smaller files.  It can also couple with\nresponse compression (details listed above) to reduce the impact of the Base64\nencoding.\n\nAnother technique is to get or store the data out-of-band.  For responses, this can\nbe as simple as a Uri pointing to a location to retrieve the data, especially if\nthe data are photographs used in a SPA client application.  This may have additional\nsecurity complications, especially when used with JWT bearer authentication.\nThis answer often works well for GraphQL queries, but may not be desired during\nuploads (mutations).\n\nAn option for uploading is to upload file data alongside a mutation with the\n`multipart/form-data` content type as described by the\n[GraphQL multipart request specification](https://github.com/jaydenseric/graphql-multipart-request-spec).\nUploaded files are mapped into the GraphQL request's variables as `IFormFile` objects.\nYou can use the provided `FormFileGraphType` scalar graph type in your GraphQL schema\nto access these files.  The `AddFormFileGraphType()` builder extension method adds this scalar\nto the DI container and configures a CLR type mapping for it to be used for `IFormFile` objects.\n\n```csharp\nservices.AddGraphQL(b =\u003e b\n    .AddAutoSchema\u003cQuery\u003e()\n    .AddFormFileGraphType()\n    .AddSystemTextJson());\n```\n\nPlease see the 'Upload' sample for a demonstration of this technique, which also\ndemonstrates the use of the `MediaTypeAttribute` to restrict the allowable media\ntypes that will be accepted.  Note that using the `FormFileGraphType` scalar requires\nthat the uploaded files be sent only via the `multipart/form-data` content type as\nattached files, with the `ReadFormOnPost` option enabled. If you also wish to allow\nclients to send files as base-64 encoded strings, you can write a custom scalar\nbetter suited to your needs.\n\n### Native AOT support\n\nGraphQL.NET Server fully supports Native AOT publishing with .NET 8.0 and later.\nSee [ASP.NET Core support for Native AOT](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/native-aot)\nfor a list of features supported by .NET 8.0.  However, GraphQL.NET only provides limited\nsupport for Native AOT publishing due to its extensive use of reflection.  Please see\n[GraphQL.NET Ahead-of-time compilation](https://github.com/graphql-dotnet/graphql-dotnet?tab=readme-ov-file#ahead-of-time-compilation)\nfor more information.\n\n## Samples\n\nThe following samples are provided to show how to integrate this project with various\ntypical ASP.NET Core scenarios.\n\n| Name            | Framework                | Description |\n|-----------------|--------------------------|-------------|\n| Authorization   | .NET 8 Minimal           | Based on the VS template, demonstrates authorization functionality with cookie-based authentication |\n| Basic           | .NET 8 Minimal           | Demonstrates simplest possible implementation |\n| Complex         | .NET 3.1 / 6 / 8         | Demonstrates older Program/Startup files and various configuration options, and multiple UI endpoints |\n| Controller      | .NET 8 Minimal           | MVC implementation; does not include WebSocket support |\n| Cors            | .NET 8 Minimal           | Demonstrates configuring a GraphQL endpoint to use a specified CORS policy |\n| EndpointRouting | .NET 8 Minimal           | Demonstrates configuring GraphQL through endpoint routing |\n| Jwt             | .NET 8 Minimal           | Demonstrates authenticating GraphQL requests with a JWT bearer token over HTTP POST and WebSocket connections |\n| MultipleSchemas | .NET 8 Minimal           | Demonstrates configuring multiple schemas within a single server |\n| NativeAot       | .NET 8 Slim              | Demonstrates configuring GraphQL for Native AOT publishing |\n| Net48           | .NET Core 2.1 / .NET 4.8 | Demonstrates configuring GraphQL on .NET 4.8 / Core 2.1 |\n| Pages           | .NET 8 Minimal           | Demonstrates configuring GraphQL on top of a Razor Pages template |\n| Upload          | .NET 8 Minimal           | Demonstrates uploading files via the `multipart/form-data` content type |\n\nMost of the above samples rely on a sample \"Chat\" schema.\nBelow are some basic requests you can use to test the schema:\n\n### Queries\n\n#### Return number of messages\n\n```graphql\n{\n  count\n}\n```\n\n#### Return last message\n\n```graphql\n{\n  lastMessage {\n    id\n    message\n    from\n    sent\n  }\n}\n```\n\n### Mutations\n\n#### Add a message\n\n```graphql\nmutation {\n  addMessage(message: { message: \"Hello\", from: \"John Doe\" }) {\n    id\n  }\n}\n```\n\n#### Clear all messages\n\n```graphql\nmutation {\n  clearMessages\n}\n```\n\n### Subscriptions\n\n```graphql\nsubscription {\n  newMessages {\n    id\n    message\n    from\n    sent\n  }\n}\n```\n\n## Contributors\n\nThis project exists thanks to all the people who contribute. \n\u003ca href=\"https://github.com/graphql-dotnet/server/graphs/contributors\"\u003e\u003cimg src=\"https://contributors-img.web.app/image?repo=graphql-dotnet/server\" /\u003e\u003c/a\u003e\n\nPRs are welcome! Looking for something to work on? The list of [open issues](https://github.com/graphql-dotnet/server/issues)\nis a great place to start. You can help the project by simply responding to some of the [asked questions](https://github.com/graphql-dotnet/server/issues?q=is%3Aissue+is%3Aopen+label%3Aquestion).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgraphql-dotnet%2Fserver","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgraphql-dotnet%2Fserver","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgraphql-dotnet%2Fserver/lists"}