conventions
conventions copied to clipboard
Support for scoped services being injected into schema types constructor
For now it is possible to set own dependency injector for executor using WithDependencyInjector method. Then using InjectAttribute
for parameters of Query methods we can inject scoped services using provided dependency container.
But what if we need to share scoped services within whole Query class injecting them into constructor?
For now services injected into constructor of schema type are resolved using typeResolutionDelegate provided into GraphQLEngine
constructor. Engine mainly constructed one time and that's why there is no option to provide it with scoped services resolution (used in Microsoft ASP.NET Core dependency
container).
Is there any solution to use injector provided for executor by WithDependencyInjector method to resolve services for injection into constructor of schema types?
I guess it is not possible at the moment. The source is taken of the GraphQL.Dotnet infos this library gets. Maybe it would be possible to hand in an custom FieldResolver with some modifications.
The logic which that implementation would need to adjust is the method private object GetSource(GraphFieldInfo fieldInfo, IResolutionContext context)
in FieldResolver. It could always trigger source = context.DependencyInjector?.Resolve(declaringType.GetTypeInfo()) ?? fieldInfo.SchemaInfo.TypeResolutionDelegate(declaringType);
To do this the engine would need some kind of method where you can handin the resolver or maybe even better a strategy for getting the source of a context or a fieldinfo.
I guess it is even way easier and without any code change. The constructor of GraphQLEngine accepts a delegate for type resolution. Just add a delegate like (type) => IoCContainer.Resolve(type) .
It worked for me in a very small test. Maybe it solves your issue.
@dmg-hamann, in you solution IoCContainer
should be singleton/static instance, which do not allow usage of scoped (per request or manually created scopes) or child containers without hacks (e.g. marking with [ThreadStatic]
which will not cover all use cases)
Anything else which is resolved by the container can be scoped. I dont know how an asp service or prims currently works but at some point you register your dependencies at the container. Isn't the container always a singleton? Or where are the dependencies store?
Yes the container (dependencies storage) is singleton. But some services are scoped which means they will be created only inside scope (create manually or by ASP.NET per HTTP request) and they can be recreated inside another scope.
// this will not work
// var test = _serviceProvider.GetService<ISomeScopedService>();
var engine= new GraphQLEngine(_serviceProvider.GetService)
using (var scope = _serviceProvider.CreateScope())
{
// e.g. here is how scoped service can be retrieved
// var service = scope.ServiceProvider.GetService<ISomeScopedService>();
var exec = engine.NewExecutor()
// this allow to receive scoped service in Query methods but not in Query ctor
.WithDependencyInjector(new DependencyInjector(scope.ServiceProvider))
.WithQueryString(query.Query);
var result = await exec.Execute();
}
Hmm... I was going to try to fix this. But I've just rechecked the issue and found that typeResolutionDelegate
is not invoked when IDependencyInjector
is specified for executor.
Also see graphql-dotnet/graphql-dotnet#1151