Skip to content

Commit b6b72db

Browse files
authored
Fixed Scoped Service Handling (#1066)
1 parent 9a877aa commit b6b72db

File tree

7 files changed

+128
-29
lines changed

7 files changed

+128
-29
lines changed

.circleci/config.yml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,19 @@ jobs:
33
pull-request:
44
working_directory: /work
55
docker:
6-
- image: chillicream/dotnet-build:3.0
6+
- image: chillicream/dotnet-build:4.0
77
steps:
88
- checkout
99
- run:
1010
name: Check that Templates Compile
11-
command: dotnet cake -target=TemplatesCompile
11+
command: |
12+
export PATH="$PATH:/root/.dotnet/tools"
13+
dotnet cake -target=TemplatesCompile
1214
- run:
1315
name: Pull Request Build
14-
command: dotnet cake -target=CoreTests
16+
command: |
17+
export PATH="$PATH:/root/.dotnet/tools"
18+
dotnet cake -target=CoreTests
1519
- store_test_results:
1620
path: /work/testoutput
1721
- store_artifacts:

global.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
22
"sdk": {
3-
"version": "2.2.103"
3+
"version": "2.2.402"
44
}
55
}

src/Core/Core/Execution/QueryExecutionBuilder.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,6 @@ public void Populate(IServiceCollection services, bool lazyExecutor)
8888
() => new QueryExecutor
8989
(
9090
sp.GetRequiredService<ISchema>(),
91-
sp,
9291
Compile(_middlewareComponents),
9392
Compile(_fieldMiddlewareComponents)
9493
)
@@ -99,7 +98,6 @@ public void Populate(IServiceCollection services, bool lazyExecutor)
9998
return new QueryExecutor
10099
(
101100
sp.GetRequiredService<ISchema>(),
102-
sp,
103101
Compile(_middlewareComponents),
104102
Compile(_fieldMiddlewareComponents)
105103
);

src/Core/Core/Execution/QueryExecutor.cs

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,19 @@ public QueryExecutor(
2121
IServiceProvider applicationServices,
2222
QueryDelegate queryDelegate,
2323
FieldMiddleware fieldMiddleware)
24+
: this(schema, queryDelegate, fieldMiddleware)
2425
{
25-
Schema = schema
26-
?? throw new ArgumentNullException(nameof(schema));
2726
_applicationServices = applicationServices
2827
?? throw new ArgumentNullException(nameof(applicationServices));
28+
}
29+
30+
public QueryExecutor(
31+
ISchema schema,
32+
QueryDelegate queryDelegate,
33+
FieldMiddleware fieldMiddleware)
34+
{
35+
Schema = schema
36+
?? throw new ArgumentNullException(nameof(schema));
2937
_queryDelegate = queryDelegate
3038
?? throw new ArgumentNullException(nameof(queryDelegate));
3139

@@ -92,20 +100,33 @@ private async Task<IExecutionResult> ExecuteMiddlewareAsync(
92100
private IRequestServiceScope CreateServiceScope(
93101
IServiceProvider requestServices)
94102
{
95-
IServiceScope serviceScope = _applicationServices.CreateScope();
96-
IServiceProvider services = requestServices ?? Schema.Services;
97-
98-
if (services == null)
103+
if (_applicationServices is null)
99104
{
100105
return new RequestServiceScope(
101-
serviceScope.ServiceProvider,
102-
serviceScope);
106+
CreateRequestServices(requestServices),
107+
Disposable.Instance);
103108
}
109+
else
110+
{
111+
IServiceScope serviceScope = _applicationServices.CreateScope();
112+
IServiceProvider services = requestServices ?? Schema.Services;
113+
114+
if (services == null)
115+
{
116+
return new RequestServiceScope(
117+
serviceScope.ServiceProvider,
118+
serviceScope);
119+
}
104120

105-
services = serviceScope.ServiceProvider.Include(services);
106-
return new RequestServiceScope(services, serviceScope);
121+
services = serviceScope.ServiceProvider.Include(services);
122+
return new RequestServiceScope(services, serviceScope);
123+
}
107124
}
108125

126+
private IServiceProvider CreateRequestServices(
127+
IServiceProvider requestServices) =>
128+
requestServices ?? Schema.Services;
129+
109130
public void Dispose()
110131
{
111132
Dispose(true);
@@ -116,12 +137,24 @@ protected virtual void Dispose(bool disposing)
116137
{
117138
if (!_disposed)
118139
{
119-
if (disposing && _applicationServices is IDisposable d)
140+
if (disposing
141+
&& _applicationServices != null
142+
&& _applicationServices is IDisposable d)
120143
{
121144
d.Dispose();
122145
}
123146
_disposed = true;
124147
}
125148
}
149+
150+
private class Disposable
151+
: IDisposable
152+
{
153+
public void Dispose()
154+
{
155+
}
156+
157+
public static Disposable Instance { get; } = new Disposable();
158+
}
126159
}
127160
}

src/Server/AspNetCore.HttpPost/HttpPostMiddleware.cs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -228,11 +228,10 @@ await _streamSerializer.SerializeAsync(
228228
.ConfigureAwait(false);
229229
}
230230

231-
private async Task<IReadOnlyList<IReadOnlyQueryRequest>>
232-
BuildBatchRequestAsync(
233-
HttpContext context,
234-
IServiceProvider services,
235-
IReadOnlyList<GraphQLRequest> batch)
231+
private async Task<IReadOnlyList<IReadOnlyQueryRequest>> BuildBatchRequestAsync(
232+
HttpContext context,
233+
IServiceProvider services,
234+
IReadOnlyList<GraphQLRequest> batch)
236235
{
237236
var queryBatch = new IReadOnlyQueryRequest[batch.Count];
238237

@@ -248,12 +247,11 @@ private async Task<IReadOnlyList<IReadOnlyQueryRequest>>
248247
return queryBatch;
249248
}
250249

251-
private async Task<IReadOnlyList<IReadOnlyQueryRequest>>
252-
BuildBatchRequestAsync(
253-
HttpContext context,
254-
IServiceProvider services,
255-
GraphQLRequest request,
256-
IReadOnlyList<string> operationNames)
250+
private async Task<IReadOnlyList<IReadOnlyQueryRequest>> BuildBatchRequestAsync(
251+
HttpContext context,
252+
IServiceProvider services,
253+
GraphQLRequest request,
254+
IReadOnlyList<string> operationNames)
257255
{
258256
var queryBatch = new IReadOnlyQueryRequest[operationNames.Count];
259257

src/Server/AspNetCore.Tests/PostMiddlewareTests.cs

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@
22
using System.Net;
33
using System.Net.Http;
44
using System.Threading.Tasks;
5+
using Microsoft.AspNetCore.TestHost;
6+
using Microsoft.Extensions.DependencyInjection;
7+
using Microsoft.Extensions.DependencyInjection.Extensions;
8+
using HotChocolate;
9+
using HotChocolate.Types;
510
using HotChocolate.AspNetCore.Tests.Utilities;
611
using HotChocolate.Language;
7-
using Microsoft.AspNetCore.TestHost;
812
using Snapshooter;
913
using Snapshooter.Xunit;
1014
using Xunit;
@@ -802,5 +806,60 @@ await server.SendPostRequestAsync(
802806
byte[] json = await message.Content.ReadAsByteArrayAsync();
803807
Utf8GraphQLRequestParser.ParseJson(json).MatchSnapshot();
804808
}
809+
810+
[Fact]
811+
public async Task HttpPost_Ensure_Scoped_Services_Work()
812+
{
813+
// arrange
814+
TestServer server = ServerFactory.Create(
815+
services =>
816+
{
817+
services.AddScoped<ScopedService>();
818+
services.AddGraphQL(SchemaBuilder.New()
819+
.AddQueryType(c => c
820+
.Name("Query")
821+
.Field("foo")
822+
.Resolver(ctx =>
823+
{
824+
ScopedService service = ctx.Service<ScopedService>();
825+
service.Increase();
826+
return service.Count;
827+
})));
828+
},
829+
app => app
830+
.Use(next => ctx =>
831+
{
832+
ScopedService service = ctx.RequestServices.GetService<ScopedService>();
833+
service.Increase();
834+
return next(ctx);
835+
})
836+
.UseGraphQL());
837+
838+
var request =
839+
@"
840+
{
841+
foo
842+
}
843+
";
844+
var contentType = "application/graphql";
845+
846+
// act
847+
HttpResponseMessage message =
848+
await server.SendPostRequestAsync(request, contentType, null);
849+
850+
// assert
851+
ClientQueryResult result = await DeserializeAsync(message);
852+
result.MatchSnapshot();
853+
}
854+
855+
public class ScopedService
856+
{
857+
public int Count { get; private set; }
858+
859+
public void Increase()
860+
{
861+
Count += 1;
862+
}
863+
}
805864
}
806865
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"Data": {
3+
"foo": 2
4+
},
5+
"Errors": null,
6+
"Extensions": null
7+
}

0 commit comments

Comments
 (0)