Skip to content

Commit 7f8e6b8

Browse files
[Fusion] Add AddHttpResponseFormatter and AddSocketSessionInterceptor (#9757)
1 parent faf31f7 commit 7f8e6b8

5 files changed

Lines changed: 547 additions & 0 deletions

File tree

src/HotChocolate/AspNetCore/src/AspNetCore/Extensions/HotChocolateAspNetCoreServiceCollectionExtensions.Http.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,11 @@ public static IRequestExecutorBuilder AddHttpResponseFormatter(
193193
/// <returns>
194194
/// Returns the <see cref="IServiceCollection"/> so that configuration can be chained.
195195
/// </returns>
196+
/// <remarks>
197+
/// The <typeparamref name="T"/> will be activated with the <see cref="IServiceProvider"/> of the schema services.
198+
/// If your <typeparamref name="T"/> needs to access application services you need to
199+
/// make the services available in the schema services via <see cref="RequestExecutorBuilderExtensions.AddApplicationService"/>.
200+
/// </remarks>
196201
public static IRequestExecutorBuilder AddHttpResponseFormatter<
197202
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T>(
198203
this IRequestExecutorBuilder builder)
@@ -221,6 +226,14 @@ public static IRequestExecutorBuilder AddHttpResponseFormatter<
221226
/// <returns>
222227
/// Returns the <see cref="IServiceCollection"/> so that configuration can be chained.
223228
/// </returns>
229+
/// <remarks>
230+
/// The <see cref="IServiceProvider"/> passed to the <paramref name="factory"/>
231+
/// is for the schema services. If you need to access application services
232+
/// you need to either make the services available in the schema services
233+
/// via <see cref="RequestExecutorBuilderExtensions.AddApplicationService"/> or use
234+
/// <see cref="ExecutionServiceProviderExtensions.GetRootServiceProvider(IServiceProvider)"/>
235+
/// to access the application services from within the schema service provider.
236+
/// </remarks>
224237
public static IRequestExecutorBuilder AddHttpResponseFormatter<T>(
225238
this IRequestExecutorBuilder builder,
226239
Func<IServiceProvider, T> factory)

src/HotChocolate/Fusion/src/Fusion.AspNetCore/DependencyInjection/AspNetCoreFusionGatewayBuilderExtensions.HttpRequestInterceptor.cs

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1+
using System.Diagnostics.CodeAnalysis;
2+
using System.Text.Json;
13
using HotChocolate.AspNetCore;
4+
using HotChocolate.AspNetCore.Formatters;
5+
using HotChocolate.AspNetCore.Subscriptions.Protocols;
6+
using HotChocolate.Execution;
27
using HotChocolate.Fusion.Configuration;
8+
using HotChocolate.Transport.Formatters;
39
using Microsoft.Extensions.DependencyInjection.Extensions;
410

511
namespace Microsoft.Extensions.DependencyInjection;
@@ -66,4 +72,228 @@ public static IFusionGatewayBuilder AddHttpRequestInterceptor(
6672
s.AddSingleton(factory);
6773
});
6874
}
75+
76+
/// <summary>
77+
/// Adds an interceptor for GraphQL socket sessions.
78+
/// </summary>
79+
/// <param name="builder">
80+
/// The <see cref="IFusionGatewayBuilder"/>.
81+
/// </param>
82+
/// <typeparam name="T">
83+
/// The <see cref="ISocketSessionInterceptor"/> implementation.
84+
/// </typeparam>
85+
/// <returns>
86+
/// Returns the <see cref="IFusionGatewayBuilder"/> so that configuration can be chained.
87+
/// </returns>
88+
/// <remarks>
89+
/// The <typeparamref name="T"/> will be activated with the <see cref="IServiceProvider"/> of
90+
/// the schema services. If your <typeparamref name="T"/> needs to access application services
91+
/// you need to make the services available in the schema services via
92+
/// <see cref="CoreFusionGatewayBuilderExtensions.AddApplicationService"/>.
93+
/// </remarks>
94+
public static IFusionGatewayBuilder AddSocketSessionInterceptor<
95+
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T>(
96+
this IFusionGatewayBuilder builder)
97+
where T : class, ISocketSessionInterceptor
98+
{
99+
ArgumentNullException.ThrowIfNull(builder);
100+
101+
return builder.ConfigureSchemaServices(
102+
(_, s) =>
103+
{
104+
s.RemoveAll<ISocketSessionInterceptor>();
105+
s.AddSingleton<ISocketSessionInterceptor, T>();
106+
});
107+
}
108+
109+
/// <summary>
110+
/// Adds an interceptor for GraphQL socket sessions.
111+
/// </summary>
112+
/// <param name="builder">
113+
/// The <see cref="IFusionGatewayBuilder"/>.
114+
/// </param>
115+
/// <param name="factory">
116+
/// A factory that creates the interceptor instance.
117+
/// </param>
118+
/// <typeparam name="T">
119+
/// The <see cref="ISocketSessionInterceptor"/> implementation.
120+
/// </typeparam>
121+
/// <returns>
122+
/// Returns the <see cref="IFusionGatewayBuilder"/> so that configuration can be chained.
123+
/// </returns>
124+
/// <remarks>
125+
/// The <see cref="IServiceProvider"/> passed to the <paramref name="factory"/>
126+
/// is for the schema services. If you need to access application services
127+
/// you need to either make the services available in the schema services
128+
/// via <see cref="CoreFusionGatewayBuilderExtensions.AddApplicationService"/> or use
129+
/// <see cref="ExecutionServiceProviderExtensions.GetRootServiceProvider(IServiceProvider)"/>
130+
/// to access the application services from within the schema service provider.
131+
/// </remarks>
132+
public static IFusionGatewayBuilder AddSocketSessionInterceptor<T>(
133+
this IFusionGatewayBuilder builder,
134+
Func<IServiceProvider, T> factory)
135+
where T : class, ISocketSessionInterceptor
136+
{
137+
ArgumentNullException.ThrowIfNull(builder);
138+
ArgumentNullException.ThrowIfNull(factory);
139+
140+
return builder.ConfigureSchemaServices(
141+
(_, s) =>
142+
{
143+
s.RemoveAll<ISocketSessionInterceptor>();
144+
s.AddSingleton<ISocketSessionInterceptor, T>(factory);
145+
});
146+
}
147+
148+
/// <summary>
149+
/// Adds the <see cref="DefaultHttpResponseFormatter"/> with specific formatter options.
150+
/// </summary>
151+
/// <param name="builder">
152+
/// The <see cref="IFusionGatewayBuilder"/>.
153+
/// </param>
154+
/// <param name="indented">
155+
/// Defines whether the underlying <see cref="Utf8JsonWriter"/>
156+
/// should pretty print the JSON which includes:
157+
/// indenting nested JSON tokens, adding new lines, and adding
158+
/// white space between property names and values.
159+
/// By default, the JSON is written without extra white spaces.
160+
/// </param>
161+
/// <param name="incrementalDeliveryFormat">
162+
/// The default incremental delivery format to use when the client does not specify one
163+
/// via the <c>Accept</c> header. Defaults to <see cref="IncrementalDeliveryFormat.Version_0_2"/>.
164+
/// </param>
165+
/// <returns>
166+
/// Returns the <see cref="IFusionGatewayBuilder"/> so that configuration can be chained.
167+
/// </returns>
168+
public static IFusionGatewayBuilder AddHttpResponseFormatter(
169+
this IFusionGatewayBuilder builder,
170+
bool indented = false,
171+
IncrementalDeliveryFormat incrementalDeliveryFormat = IncrementalDeliveryFormat.Version_0_2)
172+
{
173+
ArgumentNullException.ThrowIfNull(builder);
174+
175+
return builder.ConfigureSchemaServices(
176+
(_, s) =>
177+
{
178+
s.RemoveAll<IHttpResponseFormatter>();
179+
s.AddSingleton<IHttpResponseFormatter>(
180+
sp => DefaultHttpResponseFormatter.Create(
181+
new HttpResponseFormatterOptions
182+
{
183+
Json = new JsonResultFormatterOptions
184+
{
185+
Indented = indented
186+
}
187+
},
188+
sp.GetRequiredService<ITimeProvider>(),
189+
incrementalDeliveryFormat));
190+
});
191+
}
192+
193+
/// <summary>
194+
/// Adds the <see cref="DefaultHttpResponseFormatter"/> with specific formatter options.
195+
/// </summary>
196+
/// <param name="builder">
197+
/// The <see cref="IFusionGatewayBuilder"/>.
198+
/// </param>
199+
/// <param name="options">
200+
/// The HTTP response formatter options.
201+
/// </param>
202+
/// <param name="incrementalDeliveryFormat">
203+
/// The default incremental delivery format to use when the client does not specify one
204+
/// via the <c>Accept</c> header. Defaults to <see cref="IncrementalDeliveryFormat.Version_0_2"/>.
205+
/// </param>
206+
/// <returns>
207+
/// Returns the <see cref="IFusionGatewayBuilder"/> so that configuration can be chained.
208+
/// </returns>
209+
public static IFusionGatewayBuilder AddHttpResponseFormatter(
210+
this IFusionGatewayBuilder builder,
211+
HttpResponseFormatterOptions options,
212+
IncrementalDeliveryFormat incrementalDeliveryFormat = IncrementalDeliveryFormat.Version_0_2)
213+
{
214+
ArgumentNullException.ThrowIfNull(builder);
215+
216+
return builder.ConfigureSchemaServices(
217+
(_, s) =>
218+
{
219+
s.RemoveAll<IHttpResponseFormatter>();
220+
s.AddSingleton<IHttpResponseFormatter>(
221+
sp => DefaultHttpResponseFormatter.Create(
222+
options,
223+
sp.GetRequiredService<ITimeProvider>(),
224+
incrementalDeliveryFormat));
225+
});
226+
}
227+
228+
/// <summary>
229+
/// Adds a custom HTTP response formatter.
230+
/// </summary>
231+
/// <param name="builder">
232+
/// The <see cref="IFusionGatewayBuilder"/>.
233+
/// </param>
234+
/// <typeparam name="T">
235+
/// The type of the custom <see cref="IHttpResponseFormatter"/>.
236+
/// </typeparam>
237+
/// <returns>
238+
/// Returns the <see cref="IFusionGatewayBuilder"/> so that configuration can be chained.
239+
/// </returns>
240+
/// <remarks>
241+
/// The <typeparamref name="T"/> will be activated with the <see cref="IServiceProvider"/> of
242+
/// the schema services. If your <typeparamref name="T"/> needs to access application services
243+
/// you need to make the services available in the schema services via
244+
/// <see cref="CoreFusionGatewayBuilderExtensions.AddApplicationService"/>.
245+
/// </remarks>
246+
public static IFusionGatewayBuilder AddHttpResponseFormatter<
247+
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T>(
248+
this IFusionGatewayBuilder builder)
249+
where T : class, IHttpResponseFormatter
250+
{
251+
ArgumentNullException.ThrowIfNull(builder);
252+
253+
return builder.ConfigureSchemaServices(
254+
(_, s) =>
255+
{
256+
s.RemoveAll<IHttpResponseFormatter>();
257+
s.AddSingleton<IHttpResponseFormatter, T>();
258+
});
259+
}
260+
261+
/// <summary>
262+
/// Adds a custom HTTP response formatter.
263+
/// </summary>
264+
/// <param name="builder">
265+
/// The <see cref="IFusionGatewayBuilder"/>.
266+
/// </param>
267+
/// <param name="factory">
268+
/// The service factory.
269+
/// </param>
270+
/// <typeparam name="T">
271+
/// The type of the custom <see cref="IHttpResponseFormatter"/>.
272+
/// </typeparam>
273+
/// <returns>
274+
/// Returns the <see cref="IFusionGatewayBuilder"/> so that configuration can be chained.
275+
/// </returns>
276+
/// <remarks>
277+
/// The <see cref="IServiceProvider"/> passed to the <paramref name="factory"/>
278+
/// is for the schema services. If you need to access application services
279+
/// you need to either make the services available in the schema services
280+
/// via <see cref="CoreFusionGatewayBuilderExtensions.AddApplicationService"/> or use
281+
/// <see cref="ExecutionServiceProviderExtensions.GetRootServiceProvider(IServiceProvider)"/>
282+
/// to access the application services from within the schema service provider.
283+
/// </remarks>
284+
public static IFusionGatewayBuilder AddHttpResponseFormatter<T>(
285+
this IFusionGatewayBuilder builder,
286+
Func<IServiceProvider, T> factory)
287+
where T : class, IHttpResponseFormatter
288+
{
289+
ArgumentNullException.ThrowIfNull(builder);
290+
ArgumentNullException.ThrowIfNull(factory);
291+
292+
return builder.ConfigureSchemaServices(
293+
(_, s) =>
294+
{
295+
s.RemoveAll<IHttpResponseFormatter>();
296+
s.AddSingleton<IHttpResponseFormatter>(factory);
297+
});
298+
}
69299
}

src/HotChocolate/Fusion/test/Fusion.AspNetCore.Tests/FusionTestBase.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,8 @@ protected class Gateway(
278278
{
279279
public HttpClient CreateClient() => testServer.CreateClient();
280280

281+
public WebSocketClient CreateWebSocketClient() => testServer.CreateWebSocketClient();
282+
281283
public IServiceProvider Services => testServer.Services;
282284

283285
public List<SourceSchemaText> SourceSchemas => sourceSchemas;

0 commit comments

Comments
 (0)