Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/All.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,8 @@
<Project Path="HotChocolate/Fusion-vnext/test/Fusion.Execution.Tests/HotChocolate.Fusion.Execution.Tests.csproj" />
<Project Path="HotChocolate/Fusion-vnext/test/Fusion.Language.Tests/HotChocolate.Fusion.Language.Tests.csproj" />
<Project Path="HotChocolate/Fusion-vnext/test/Fusion.Packaging.Tests/HotChocolate.Fusion.Packaging.Tests.csproj" />
<Project Path="HotChocolate/Fusion-vnext/test/Fusion.Utilities.Tests/HotChocolate.Fusion.Utilities.Tests.csproj" />
<Project Path="HotChocolate/Fusion-vnext/test/Fusion.Tests.Shared/HotChocolate.Fusion.Tests.Shared.csproj" />
<Project Path="HotChocolate/Fusion-vnext/test/Fusion.Utilities.Tests/HotChocolate.Fusion.Utilities.Tests.csproj" />
</Folder>
<Folder Name="/HotChocolate/Json/" />
<Folder Name="/HotChocolate/Json/src/" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,108 +1,115 @@
using System.Diagnostics.CodeAnalysis;
using HotChocolate.AspNetCore.Warmup;
using HotChocolate.Execution.Configuration;
using HotChocolate.Execution.Internal;

// ReSharper disable once CheckNamespace
namespace Microsoft.Extensions.DependencyInjection;

public static partial class HotChocolateAspNetCoreServiceCollectionExtensions
{
/// <summary>
/// Adds the current GraphQL configuration to the warmup background service.
/// Adds a warmup task that will be executed on each newly created request executor.
/// </summary>
/// <param name="builder">
/// The <see cref="IRequestExecutorBuilder"/>.
/// </param>
/// <param name="warmup">
/// The warmup task that shall be executed on a new executor.
/// </param>
/// <param name="keepWarm">
/// Apply warmup task after eviction and keep executor in-memory.
/// <param name="warmupFunc">
/// The warmup delegate to execute.
/// </param>
/// <param name="skipIf">
/// Skips the warmup task if set to true.
/// If <c>true</c>, the warmup task will not be registered.
/// </param>
/// <returns>
/// Returns the <see cref="IRequestExecutorBuilder"/> so that configuration can be chained.
/// </returns>
/// <exception cref="ArgumentNullException">
/// The <see cref="IRequestExecutorBuilder"/> is <c>null</c>.
/// The <paramref name="builder"/> is <c>null</c>.
/// </exception>
/// <exception cref="ArgumentNullException">
/// The <paramref name="warmupFunc"/> is <c>null</c>.
/// </exception>
public static IRequestExecutorBuilder InitializeOnStartup(
public static IRequestExecutorBuilder AddWarmupTask(
this IRequestExecutorBuilder builder,
Func<IRequestExecutor, CancellationToken, Task>? warmup = null,
bool keepWarm = false,
Func<IRequestExecutor, CancellationToken, Task> warmupFunc,
bool skipIf = false)
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(warmupFunc);

if (!skipIf)
{
builder.Services.AddHostedService<RequestExecutorWarmupService>();
builder.Services.AddSingleton(new WarmupSchemaTask(builder.Name, keepWarm, warmup));
}

return builder;
return builder.AddWarmupTask(new DelegateRequestExecutorWarmupTask(warmupFunc), skipIf);
}

/// <summary>
/// Adds the current GraphQL configuration to the warmup background service.
/// Adds a warmup task that will be executed on each newly created request executor.
/// </summary>
/// <param name="builder">
/// The <see cref="IRequestExecutorBuilder"/>.
/// </param>
/// <param name="options">
/// The <see cref="RequestExecutorInitializationOptions"/>.
/// <param name="warmupTask">
/// The warmup task to execute.
/// </param>
/// <param name="skipIf">
/// Skips the warmup task if set to true.
/// If <c>true</c>, the warmup task will not be registered.
/// </param>
/// <returns>
/// Returns the <see cref="IRequestExecutorBuilder"/> so that configuration can be chained.
/// </returns>
/// <exception cref="ArgumentNullException">
/// The <see cref="IRequestExecutorBuilder"/> is <c>null</c>.
/// The <paramref name="builder"/> is <c>null</c>.
/// </exception>
public static IRequestExecutorBuilder InitializeOnStartup(
/// <exception cref="ArgumentNullException">
/// The <paramref name="warmupTask"/> is <c>null</c>.
/// </exception>
public static IRequestExecutorBuilder AddWarmupTask(
this IRequestExecutorBuilder builder,
RequestExecutorInitializationOptions options,
IRequestExecutorWarmupTask warmupTask,
bool skipIf = false)
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(warmupTask);

if (skipIf)
{
return builder;
}

Func<IRequestExecutor, CancellationToken, Task>? warmup;
return builder.ConfigureSchemaServices((_, sc) => sc.AddSingleton(warmupTask));
}

if (options.WriteSchemaFile.Enable)
{
var schemaFileName =
options.WriteSchemaFile.FileName
?? System.IO.Path.Combine(Environment.CurrentDirectory, "schema.graphqls");
/// <summary>
/// Adds a warmup task for the request executor.
/// </summary>
/// <param name="builder">
/// The <see cref="IRequestExecutorBuilder"/>.
/// </param>
/// <param name="skipIf">
/// If <c>true</c>, the warmup task will not be registered.
/// </param>
/// <typeparam name="T">
/// The warmup task to execute.
/// </typeparam>
/// <returns>
/// Returns the <see cref="IRequestExecutorBuilder"/> so that configuration can be chained.
/// </returns>
/// <exception cref="ArgumentNullException">
/// The <paramref name="builder"/> is <c>null</c>.
/// </exception>
public static IRequestExecutorBuilder AddWarmupTask<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T>(
this IRequestExecutorBuilder builder,
bool skipIf = false)
where T : class, IRequestExecutorWarmupTask
{
ArgumentNullException.ThrowIfNull(builder);

if (options.Warmup is null)
{
warmup = async (executor, cancellationToken)
=> await SchemaFileExporter.Export(schemaFileName, executor, cancellationToken);
}
else
{
warmup = async (executor, cancellationToken) =>
{
await SchemaFileExporter.Export(schemaFileName, executor, cancellationToken);
await options.Warmup(executor, cancellationToken);
};
}
}
else
if (skipIf)
{
warmup = options.Warmup;
return builder;
}

return InitializeOnStartup(builder, warmup, options.KeepWarm);
builder.ConfigureSchemaServices(
static (_, sc) => sc.AddSingleton<IRequestExecutorWarmupTask, T>());

return builder;
}

/// <summary>
Expand All @@ -114,26 +121,24 @@ public static IRequestExecutorBuilder InitializeOnStartup(
/// <param name="schemaFileName">
/// The file name of the schema file.
/// </param>
/// <param name="skipIf">
/// If <c>true</c>, the schema file will not be exported.
/// </param>
/// <returns>
/// Returns the <see cref="IRequestExecutorBuilder"/> so that configuration can be chained.
/// </returns>
/// <exception cref="ArgumentNullException">
/// The <see cref="IRequestExecutorBuilder"/> is <c>null</c>.
/// The <paramref name="builder"/> is <c>null</c>.
/// </exception>
public static IRequestExecutorBuilder ExportSchemaOnStartup(
this IRequestExecutorBuilder builder,
string? schemaFileName = null)
string? schemaFileName = null,
bool skipIf = false)
{
ArgumentNullException.ThrowIfNull(builder);

return InitializeOnStartup(builder, new RequestExecutorInitializationOptions
{
KeepWarm = true,
WriteSchemaFile = new SchemaFileInitializationOptions
{
Enable = true,
FileName = schemaFileName
}
});
schemaFileName ??= System.IO.Path.Combine(Environment.CurrentDirectory, "schema.graphqls");

return builder.AddWarmupTask(new SchemaFileExporterWarmupTask(schemaFileName), skipIf);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using HotChocolate.AspNetCore.Instrumentation;
using HotChocolate.AspNetCore.ParameterExpressionBuilders;
using HotChocolate.AspNetCore.Parsers;
using HotChocolate.AspNetCore.Warmup;
using HotChocolate.Execution.Configuration;
using HotChocolate.Internal;
using HotChocolate.Language;
Expand All @@ -19,53 +20,6 @@ namespace Microsoft.Extensions.DependencyInjection;
/// </summary>
public static partial class HotChocolateAspNetCoreServiceCollectionExtensions
{
private static IRequestExecutorBuilder AddGraphQLServerCore(
this IRequestExecutorBuilder builder,
int maxAllowedRequestSize = MaxAllowedRequestSize)
{
builder.ConfigureSchemaServices(s =>
{
s.TryAddSingleton<IHttpResponseFormatter>(
sp => DefaultHttpResponseFormatter.Create(
new HttpResponseFormatterOptions { HttpTransportVersion = HttpTransportVersion.Latest },
sp.GetRequiredService<ITimeProvider>()));
s.TryAddSingleton<IHttpRequestParser>(
sp => new DefaultHttpRequestParser(
sp.GetRequiredService<IDocumentCache>(),
sp.GetRequiredService<IDocumentHashProvider>(),
maxAllowedRequestSize,
sp.GetRequiredService<ParserOptions>()));

s.TryAddSingleton<IServerDiagnosticEvents>(sp =>
{
var listeners = sp.GetServices<IServerDiagnosticEventListener>().ToArray();
return listeners.Length switch
{
0 => new NoopServerDiagnosticEventListener(),
1 => listeners[0],
_ => new AggregateServerDiagnosticEventListener(listeners)
};
});
});

if (!builder.Services.IsImplementationTypeRegistered<HttpContextParameterExpressionBuilder>())
{
builder.Services.AddSingleton<IParameterExpressionBuilder, HttpContextParameterExpressionBuilder>();
}

if (!builder.Services.IsImplementationTypeRegistered<HttpRequestParameterExpressionBuilder>())
{
builder.Services.AddSingleton<IParameterExpressionBuilder, HttpRequestParameterExpressionBuilder>();
}

if (!builder.Services.IsImplementationTypeRegistered<HttpResponseParameterExpressionBuilder>())
{
builder.Services.AddSingleton<IParameterExpressionBuilder, HttpResponseParameterExpressionBuilder>();
}

return builder;
}

/// <summary>
/// Adds a GraphQL server configuration to the DI.
/// </summary>
Expand Down Expand Up @@ -95,6 +49,7 @@ public static IRequestExecutorBuilder AddGraphQLServer(
var builder = services
.AddGraphQL(schemaName)
.AddGraphQLServerCore(maxAllowedRequestSize)
.AddStartupInitialization()
.AddDefaultHttpRequestInterceptor()
.AddSubscriptionServices();

Expand Down Expand Up @@ -160,4 +115,59 @@ public static IRequestExecutorBuilder AddUploadType(
builder.AddType<UploadType>();
return builder;
}

private static IRequestExecutorBuilder AddGraphQLServerCore(
this IRequestExecutorBuilder builder,
int maxAllowedRequestSize = MaxAllowedRequestSize)
{
builder.ConfigureSchemaServices(s =>
{
s.TryAddSingleton<IHttpResponseFormatter>(
sp => DefaultHttpResponseFormatter.Create(
new HttpResponseFormatterOptions { HttpTransportVersion = HttpTransportVersion.Latest },
sp.GetRequiredService<ITimeProvider>()));
s.TryAddSingleton<IHttpRequestParser>(
sp => new DefaultHttpRequestParser(
sp.GetRequiredService<IDocumentCache>(),
sp.GetRequiredService<IDocumentHashProvider>(),
maxAllowedRequestSize,
sp.GetRequiredService<ParserOptions>()));

s.TryAddSingleton<IServerDiagnosticEvents>(sp =>
{
var listeners = sp.GetServices<IServerDiagnosticEventListener>().ToArray();
return listeners.Length switch
{
0 => new NoopServerDiagnosticEventListener(),
1 => listeners[0],
_ => new AggregateServerDiagnosticEventListener(listeners)
};
});
});

if (!builder.Services.IsImplementationTypeRegistered<HttpContextParameterExpressionBuilder>())
{
builder.Services.AddSingleton<IParameterExpressionBuilder, HttpContextParameterExpressionBuilder>();
}

if (!builder.Services.IsImplementationTypeRegistered<HttpRequestParameterExpressionBuilder>())
{
builder.Services.AddSingleton<IParameterExpressionBuilder, HttpRequestParameterExpressionBuilder>();
}

if (!builder.Services.IsImplementationTypeRegistered<HttpResponseParameterExpressionBuilder>())
{
builder.Services.AddSingleton<IParameterExpressionBuilder, HttpResponseParameterExpressionBuilder>();
}

return builder;
}

private static IRequestExecutorBuilder AddStartupInitialization(
this IRequestExecutorBuilder builder)
{
builder.Services.AddHostedService<RequestExecutorWarmupService>();

return builder;
}
}

This file was deleted.

Loading
Loading