graphql-platform icon indicating copy to clipboard operation
graphql-platform copied to clipboard

Using the DbContext through constructor injection in the service layer results in errors

Open bramvelderen-nlo opened this issue 3 years ago • 5 comments

Is your feature request related to a problem?

So in our project we want to design our application in a way that we can easily add different API interfaces like GraphQL or a RestAPI on our existing business logic.

To achieve this we moved as much logic as possible to regular Services which live in the DI container. This services are made using regular microsoft standards, like injecting the DbContext normally through the constructor.

Now we do have a small problem, for Queries we want the service to pass back a IQueryable of the DbSet in the DbContext and pass this to the Query class so we can use the projection option and only retrieve the fields that the query requests.

Problem is that when injecting the DbContext in the service the regular way it will start throwing an Cannot access a disposed context instance error.

I have an example project here: https://github.com/bramvelderen-nlo/Playday.GraphQL

  • The service: https://github.com/bramvelderen-nlo/Playday.GraphQL/blob/main/src/Playday.GraphQL.API/Graph/Scooters/ScooterService.cs
  • The query class: https://github.com/bramvelderen-nlo/Playday.GraphQL/blob/main/src/Playday.GraphQL.API/Graph/Scooters/ScooterQueries.cs
  • The program class: https://github.com/bramvelderen-nlo/Playday.GraphQL/blob/main/src/Playday.GraphQL.API/Program.cs

The solution you'd like

What i hope is possible is that i can just build my service layer the same way as i would for an MVC project and reuse the exact logic for the GraphQL resolvers. But right now that gives me the DbContext error. So is there already an existing solution here where i don't need to pass the DbContext from the Query class to the service and instead can just rely on the injected DbContext?

Product

Hot Chocolate

bramvelderen-nlo avatar Jul 27 '22 11:07 bramvelderen-nlo

I think this is happening, since the service scope is disposed after the resolver itself finishes executing: https://github.com/ChilliCream/hotchocolate/blob/80350d82253419a9ff631bbbaae0f640eb834753/src/HotChocolate/Core/src/Types/Types/Extensions/ObjectFieldDescriptorExtensions.cs#L136-L158

Seems like a similar problem to https://github.com/ChilliCream/hotchocolate/issues/4638 for me.

If you do not depend on the UseServiceScope, you could simply register your service using the ServiceKind.Synchronized: https://chillicream.com/docs/hotchocolate/server/dependency-injection/#registerservice

tobias-tengler avatar Jul 27 '22 14:07 tobias-tengler

@tobias-tengler I've seen the Synchronized option indeed. But doesn't that mean that the resolvers will all run synchronous instead of parallel. While using the UseServiceScope will still run paralel but each of the injected services still have their own scoped dbcontext.

But shouldn't it be the case that the Projections of HotChocolate should also run in the same ServiceScope as all the services injected within? Or is this somehow possible with settings or attributes?

bramvelderen-nlo avatar Jul 28 '22 11:07 bramvelderen-nlo

I just looked at your code again and saw that you don't have the UseProjection attribute there atm, so I can't tell how you've used it. Did you put the UseServiceScope attribute on top of the UseProjection attribute? Normally the services should only be disposed once the inner middleware has finished.

@tobias-tengler I've seen the Synchronized option indeed. But doesn't that mean that the resolvers will all run synchronous instead of parallel. While using the UseServiceScope will still run paralel but each of the injected services still have their own scoped dbcontext.

Have you tested the performance of it? Normally there are only a few fields in a query that will use the DbContext. The performance impact should be negligable most of the time.

tobias-tengler avatar Jul 28 '22 11:07 tobias-tengler

Did you put the UseServiceScope attribute on top of the UseProjection attribute? Normally the services should only be disposed once the inner middleware has finished. That is what i was hoping for. But as soon as i return a IQueryable i get this issue that the DbContext is already disposed, so apparently in the HotChocolate middleware which executes the IQueryable runs outside of the ServiceScope, causing this error

Right now i indeed don't have the UseProjection anywere since i didn't need it to reproduce the issue as seen in the example. But ideally i have exactly this example code with the useProjection also yes.

Have you tested the performance of it? Normally there are only a few fields in a query that will use the DbContext. The performance impact should be negligable most of the time.

I did not test the performance impact, it will be negligable indeed, so i could go for that option. But i feel like the other option should somehow work too.

bramvelderen-nlo avatar Jul 28 '22 12:07 bramvelderen-nlo

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Nov 25 '22 12:11 stale[bot]

@tobias-tengler I've seen the Synchronized option indeed. But doesn't that mean that the resolvers will all run synchronous instead of parallel. While using the UseServiceScope will still run paralel but each of the injected services still have their own scoped dbcontext.

But shouldn't it be the case that the Projections of HotChocolate should also run in the same ServiceScope as all the services injected within? Or is this somehow possible with settings or attributes?

You can register your context as scoped while using the pooled db context factory. So the db context has the same lifetime as the scope and the resolver since you're using UseServiceScope. https://learn.microsoft.com/en-us/ef/core/performance/advanced-performance-topics?tabs=with-di%2Cexpression-api-with-constant#managing-state-in-pooled-contexts

sc-mnelson avatar Nov 02 '23 14:11 sc-mnelson