-
-
Notifications
You must be signed in to change notification settings - Fork 923
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add MS-specific dependency injection extensions #1571
Conversation
@sungam3r We've already added the
I'm okay either way. Now that we have the |
I'm absolutely sure that after #1730, we have to go ahead and include these changes, so option 2 or resolve conflicts/rebase here. |
I merged changes here, and removed |
Only additions now, no deletions. Good. Will review soon. |
C:\Program Files\dotnet\sdk\3.1.302\Sdks\NuGet.Build.Tasks.Pack\build\NuGet.Build.Tasks.Pack.targets(187,6): warning : This project cannot be packaged because packaging has been disabled. Add <IsPackable>true</IsPackable> to the project file to enable producing a package from this project. [C:\projects\graphql-dotnet\src\GraphQL.Harness\GraphQL.Harness.csproj]
C:\Program Files\dotnet\sdk\3.1.302\Sdks\NuGet.Build.Tasks.Pack\build\NuGet.Build.Tasks.Pack.targets(198,5): error NU5046: The icon file 'logo.64x64.png' does not exist in the package. [C:\projects\graphql-dotnet\src\GraphQL.Extensions.DI.Microsoft\GraphQL.Extensions.DI.Microsoft.csproj] |
I've added a rough draft of a 'resolver injection' technique to this PR. It requires review. Since it's impossible with extension methods, I added builder classes to facilitate this. Perhaps you have a better idea @sungam3r but I'm not sure how else to do it. Anyway, with this sample, you could write code like this: Field<StringGraphType, string>("test")
.Argument(...)
.Resolve()
.WithScope()
.WithService<MyService>()
.WithService<MyOtherService>()
.ResolveAsync(async (context, service, service2) => await service.GetAnswer(context.Source))
.Description("hello"); Of course, the This resolve builder is within the Personally I think we should combine the two projects together. Someone can always register their own implementation of an Finally, I would not let this hold up 3.0. Nothing here is going to be a breaking change, so there's no reason it can't make it into 3.1 if we have not the time to review it fully. I would like to keep this on the top of the pile, however, and if we can get this done quickly, that's great! |
@sungam3r If you like the idea, let me know, and I can add tests and so on. I just threw this together real quick. |
Co-authored-by: Ivan Maximov <sungam3r@yandex.ru>
@sungam3r We had planned to release this for 3.1, but never did. Can we release this with 4.0? We need to review:
I should add some tests and a few xml comments. |
Give me 1-2 days. And side note - dotnet/runtime#47113. I found this by accident. Perhaps this is the reason for the falling test. |
src/GraphQL.Extensions.DI.Microsoft/GraphQL.Extensions.DI.Microsoft.csproj
Outdated
Show resolved
Hide resolved
src/GraphQL.Extensions.DI.Microsoft/ScopedResolveFieldContextAdapter.cs
Outdated
Show resolved
Hide resolved
src/GraphQL.Extensions.DI.Microsoft/ScopedResolveFieldContextAdapter.cs
Outdated
Show resolved
Hide resolved
src/GraphQL.Extensions.DI.Microsoft/ScopedAsyncFieldResolver.cs
Outdated
Show resolved
Hide resolved
src/GraphQL.Extensions.DI.Microsoft/ScopedAsyncFieldResolver.cs
Outdated
Show resolved
Hide resolved
|
||
namespace GraphQL.Extensions.DI.Microsoft | ||
{ | ||
public class ScopedFieldResolver<TReturnType> : FuncFieldResolver<TReturnType> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is ScopedFieldResolver<TReturnType>
class used anywhere (ScopedAsyncFieldResolver<TReturnType>
as well) ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes - ScopedFieldBuilderExtensions.cs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I talked about ScopedFieldResolver<TReturnType>
not ScopedFieldResolver<TSourceType, TReturnType>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh. They might not be.
Good comments. I'll work on it. |
I probably won't be working on other tasks until v4. Let's wrap up this one. |
Co-authored-by: Ivan Maximov <sungam3r@yandex.ru>
…osoft.csproj Co-authored-by: Ivan Maximov <sungam3r@yandex.ru>
…dapter.cs Co-authored-by: Ivan Maximov <sungam3r@yandex.ru>
…dapter.cs Co-authored-by: Ivan Maximov <sungam3r@yandex.ru>
Replaced with #2261 |
This is a follow-up to the discussion in #1345
This PR adds
Services
back toISchema
and addsRequestServices
toIResolveFieldContext
andExecutionOptions
. This allows implementers to access the currently executing request's scoped service provider. No additional dependencies or functionality is added to the base GraphQL project.The naming of the
IResolveFieldContext.RequestServices
property matches Asp.Net Core, where theirHttpContext
has aRequestServices
property to access the service provider of the executing request.I also added the recently-removed
Services
property back into theISchema
interface, so code can access the service provider used to create the graph type and other schema-specific classes if desired.By adding
RequestServices
into the GraphQL pipeline, resolvers that are based on scoped services are free from framework-specific dependencies, such asIHttpContextAccessor.HttpContext.RequestServices
, or needing to pass the service provider or services through theIResolveFieldContext.UserContext
property. It also alleviates the need to create a custom service accessor singleton.Anyone that wishes to keep their dependent services listed in the constructor can simply register the schema as a scoped service, as they have always done. For those of us that want to keep the performance of the schema as a singleton,
I've also added a GraphQL.Extensions.DI.Microsoft project, which provides an easy way to have parallel graphql resolvers execute scoped services not designed for multithreaded operation (as most scoped services are not, such as Entity Framework). Simply call
Field().ResolveScoped
orField().ResolveAsyncScoped
with the same field resolver, and the extension will create a DI scope during the execution of the resolver, disposing of it appropriately when complete. This project works with any DI container compatible with the necessary interface - notably, autofac is also compatible. I feel that these additional extension methods would be convenient, but not necessary as they can always use theSerialExecutionStrategy
and ignore this issue. I would include this functionality as notes in the documentation, but it seems like a bit too much code for that. Perhaps it can be simply a link in the documentation to a project with these extra classes, or perhaps it should be released as another nuget package.I had one additional idea, not in this PR, to reduce the calls to
RequestServices
: We could add additionalResolve
overloads for resolvers that need services. For example, one could write:The resolver would simply pull the requested services from the context's RequestServices property prior to calling the lambda function.
Unfortunately it cannot be implemented as an extension method very well, as the call to
ResolveAsync
would need to include theTSourceType
andTReturnType
types also. So it doesn't lend itself well to adding these methods to a third party library. If we add this feature, it would have to be directly on theFieldBuilder<TSourceType, TReturnType>
class.